diff --git a/config/scripts/ci/sharding/ci-shard-timings.json b/config/scripts/ci/sharding/ci-shard-timings.json index a5265de0533..73bb8ded1a9 100644 --- a/config/scripts/ci/sharding/ci-shard-timings.json +++ b/config/scripts/ci/sharding/ci-shard-timings.json @@ -425,7 +425,6 @@ "src/cli/format.test.ts": 446, "src/cli/handler-group-manifest.test.ts": 3610, "src/cli/handlers/account.test.ts": 849, - "src/cli/handlers/agent-hooks-load-boundary.test.ts": 457, "src/cli/handlers/agent-hooks-prepare-codex-isolated-home.test.ts": 854, "src/cli/handlers/agent-hooks.test.ts": 1702, "src/cli/handlers/artifacts.test.ts": 471, diff --git a/mobile/src/session/native-chat/input/MobileNativeChatPermission.links.test.tsx b/mobile/src/session/native-chat/input/MobileNativeChatPermission.links.test.tsx deleted file mode 100644 index c2d1e6ee9c8..00000000000 --- a/mobile/src/session/native-chat/input/MobileNativeChatPermission.links.test.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { createElement } from 'react' -import { act, create, type ReactTestInstance, type ReactTestRenderer } from 'react-test-renderer' -import { afterEach, expect, it, vi } from 'vitest' -import { MobileNativeChatOpenFileContext } from '../mobile-native-chat-open-file-context' -import { MobileNativeChatPermission } from './MobileNativeChatPermission' - -vi.mock('react-native', () => ({ - Linking: { openURL: () => Promise.resolve() }, - Platform: { OS: 'ios', select: (o: Record) => o.ios }, - Pressable: 'Pressable', - ScrollView: 'ScrollView', - StyleSheet: { create: (styles: unknown) => styles, hairlineWidth: 1 }, - Text: 'Text', - View: 'View' -})) -vi.mock('lucide-react-native', () => ({ - ChevronDown: 'ChevronDown', - ShieldQuestion: 'ShieldQuestion', - X: 'X' -})) -vi.mock('../../../components/pr-sidebar/MermaidDiagram', () => ({ - MermaidDiagram: 'MermaidDiagram' -})) -vi.mock('../../../components/MobileSourceCopyButton', () => ({ - MobileSourceCopyButton: 'MobileSourceCopyButton' -})) - -let renderer: ReactTestRenderer | null = null -afterEach(() => { - act(() => renderer?.unmount()) - renderer = null -}) - -const flatten = (node: ReactTestInstance | string): string => - typeof node === 'string' ? node : node.children.map(flatten).join('') - -// A terminal-backed plan review reaches the phone as a permission with a plan subject. -it('opens a file named in a plan approval through the chat', () => { - const openFile = vi.fn() - act(() => { - renderer = create( - createElement( - MobileNativeChatOpenFileContext, - { value: openFile }, - createElement(MobileNativeChatPermission, { - permission: { - title: 'Review proposed plan', - subject: { kind: 'plan', text: 'First edit src/app.ts, then run tests.' }, - options: [{ label: 'Approve', send: 'approve' }] - }, - onRespond: async () => true - }) - ) - ) - }) - const link = renderer!.root.find( - (node) => - String(node.type) === 'Text' && - typeof node.props.onPress === 'function' && - flatten(node) === 'src/app.ts' - ) - act(() => link.props.onPress()) - expect(openFile).toHaveBeenCalledExactlyOnceWith('src/app.ts') -}) diff --git a/mobile/src/session/native-chat/transcript/MobileNativeChatTurnDiffRollup.test.tsx b/mobile/src/session/native-chat/transcript/MobileNativeChatTurnDiffRollup.test.tsx deleted file mode 100644 index 2bbb2378601..00000000000 --- a/mobile/src/session/native-chat/transcript/MobileNativeChatTurnDiffRollup.test.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import './mobile-agent-message-renderer.test-fixture' -import { createElement } from 'react' -import { act, create, type ReactTestRenderer } from 'react-test-renderer' -import { afterEach, expect, it, vi } from 'vitest' -import { messages, Transcript } from './mobile-native-chat-turn-diff.test-fixture' -import { MobileNativeChatTurnDiffRollup } from './MobileNativeChatTurnDiffRollup' -import type * as TurnDiffRollupModule from './MobileNativeChatTurnDiffRollup' - -vi.mock('./MobileNativeChatTurnDiffRollup', async (importOriginal) => { - const actual = await importOriginal() - return { ...actual, MobileNativeChatTurnDiffRollup: vi.fn(actual.MobileNativeChatTurnDiffRollup) } -}) - -let renderer: ReactTestRenderer | null = null -afterEach(() => { - act(() => renderer?.unmount()) - renderer = null -}) - -it.each([10, 100])( - 'does not repaint unrelated outcome rows while another turn streams (%i turns)', - (count) => { - const rows = Array.from({ length: count }, (_, index) => - messages.map((message) => ({ - ...message, - id: `${index}:${message.id}` - })) - ).flat() - act(() => { - renderer = create(createElement(Transcript, { rows })) - }) - const outcome = vi.mocked(MobileNativeChatTurnDiffRollup) - const before = outcome.mock.calls.length - const last = rows.at(-1)! - const updated = [ - ...rows.slice(0, -1), - { ...last, blocks: [{ type: 'text' as const, text: 'Updated again.' }] } - ] - act(() => { - renderer!.update(createElement(Transcript, { rows: updated })) - }) - expect(outcome.mock.calls.length - before).toBe(0) - const changed = updated.map((message) => - message.id === `${count - 1}:edit` - ? { - ...message, - blocks: message.blocks.map((block) => - block.type === 'tool-call' && block.name === 'Edit' - ? { - ...block, - input: { - file_path: '/repo/greeting.ts', - old_string: 'helloOld()', - new_string: 'helloNewest()' - } - } - : block - ) - } - : message - ) - act(() => { - renderer!.update(createElement(Transcript, { rows: changed })) - }) - expect(outcome.mock.calls.length - before).toBe(1) - const latest = outcome.mock.calls.at(-1)![0].diff - expect(latest.files.map((file) => file.path)).toContain('/repo/greeting.ts') - } -) diff --git a/src/cli/handlers/agent-hooks-load-boundary.test.ts b/src/cli/handlers/agent-hooks-load-boundary.test.ts deleted file mode 100644 index 133f0fa2311..00000000000 --- a/src/cli/handlers/agent-hooks-load-boundary.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { afterEach, expect, it, vi } from 'vitest' -import { main } from '../index' - -const { call } = vi.hoisted(() => ({ call: vi.fn(async () => ({ result: null })) })) -vi.mock('../runtime-client', () => ({ - RuntimeClient: class { - call = call - }, - RuntimeClientError: Error, - getDefaultUserDataPath: () => '/unused/user-data' -})) -vi.mock('../../main/persistence/profile-state/profile-state-offline-settings', () => { - throw new Error('Offline profile settings loaded during online preparation') -}) -vi.mock('../../main/persistence/profile-state/profile-state-access', () => { - throw new Error('Profile admission loaded during online preparation') -}) -vi.mock('../profile-state-location', () => { - throw new Error('Profile location loaded during online preparation') -}) -vi.mock('../../main/codex/hooks/installation/codex-hook-local-install', () => { - throw new Error('The Codex installer loaded in the pane CLI') -}) - -afterEach(() => { - call.mockClear() - vi.unstubAllEnvs() - vi.restoreAllMocks() - process.exitCode = undefined -}) - -it('prepares a WSL pane through the runtime without loading profile storage or an installer', async () => { - vi.stubEnv('WSL_DISTRO_NAME', 'Ubuntu') - const error = vi.spyOn(console, 'error').mockImplementation(() => {}) - await main(['agent', 'hooks', 'prepare-codex']) - expect(error).not.toHaveBeenCalled() - expect(call).toHaveBeenCalledWith('agentHooks.prepareCodexForWslPane', expect.any(Object), { - timeoutMs: 50_000 - }) -}) - -it('loads nothing and asks nothing for a native pane', async () => { - vi.stubEnv('WSL_DISTRO_NAME', '') - const error = vi.spyOn(console, 'error').mockImplementation(() => {}) - await main(['agent', 'hooks', 'prepare-codex']) - expect(error).not.toHaveBeenCalled() - expect(call).not.toHaveBeenCalled() -}) diff --git a/src/cli/handlers/terminal-split.test.ts b/src/cli/handlers/terminal-split.test.ts index 915bcffc539..55baac8441b 100644 --- a/src/cli/handlers/terminal-split.test.ts +++ b/src/cli/handlers/terminal-split.test.ts @@ -42,22 +42,6 @@ describe('terminal split --retry-split', () => { vi.restoreAllMocks() }) - it('sends the retry to a host that can resume the split', async () => { - const call = vi.fn().mockResolvedValue({ - result: { split: { handle: 'term_2', tabId: 'tab-1', paneRuntimeId: 1, leafId: 'leaf-1' } } - }) - vi.spyOn(console, 'log').mockImplementation(() => {}) - - await retrySplit(splitClient(call, [TERMINAL_SPLIT_RETRY_RUNTIME_CAPABILITY])) - - expect(call).toHaveBeenCalledExactlyOnceWith('terminal.split', { - terminal: 'term_1', - direction: undefined, - command: 'agent --task 1', - retrySplit: 'leaf-1' - }) - }) - // An older host strips `retrySplit` and splits again, starting a second copy of the command. it('refuses rather than splitting again on a host without the capability', async () => { const call = vi.fn() diff --git a/src/cli/index-environment-commands.test.ts b/src/cli/index-environment-commands.test.ts index cb677a8cab9..c2282c520d5 100644 --- a/src/cli/index-environment-commands.test.ts +++ b/src/cli/index-environment-commands.test.ts @@ -80,32 +80,4 @@ describe('orca cli worktree awareness', () => { expect(logSpy.mock.calls[0]?.[0]).not.toContain('token') expect(logSpy.mock.calls[0]?.[0]).not.toContain('publicKeyB64') }) - - it('adds saved environments even when ORCA_ENVIRONMENT is set', async () => { - process.env.ORCA_ENVIRONMENT = 'stale-env' - const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) - - await main( - ['environment', 'add', '--name', 'desk', '--pairing-code', 'orca://pair#abc', '--json'], - '/tmp/repo' - ) - - expect(addEnvironmentFromPairingCodeMock).toHaveBeenCalledWith('/tmp/orca-user-data', { - name: 'desk', - pairingCode: 'orca://pair#abc' - }) - expect(callMock).not.toHaveBeenCalled() - expect(JSON.parse(String(logSpy.mock.calls[0]?.[0]))).toMatchObject({ - ok: true, - result: { - environment: { - id: 'env-1', - name: 'desk', - endpoints: [{ id: 'ws-env-1', kind: 'websocket', endpoint: 'ws://127.0.0.1:6768' }] - } - } - }) - expect(logSpy.mock.calls[0]?.[0]).not.toContain('token') - expect(logSpy.mock.calls[0]?.[0]).not.toContain('publicKeyB64') - }) }) diff --git a/src/main/codex/__fixtures__/codex-app-server-sleep.json b/src/main/codex/__fixtures__/codex-app-server-sleep.json deleted file mode 100644 index 6e92d751a72..00000000000 --- a/src/main/codex/__fixtures__/codex-app-server-sleep.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "method": "item/started", - "params": { - "item": { - "type": "sleep", - "id": "call_000ed8ed8f1b4530bf32cd6ca8fd5c15", - "durationMs": 1000 - }, - "threadId": "01a1a381-0622-7153-af21-ae6389d8c1b3", - "turnId": "01a1a381-06ec-74b1-89f1-843749197dac", - "startedAtMs": 1793744507474 - }, - "emittedAtMs": 1793744507477 - }, - { - "method": "item/completed", - "params": { - "item": { - "type": "sleep", - "id": "call_000ed8ed8f1b4530bf32cd6ca8fd5c15", - "durationMs": 1000 - }, - "threadId": "01a1a381-0622-7153-af21-ae6389d8c1b3", - "turnId": "01a1a381-06ec-74b1-89f1-843749197dac", - "completedAtMs": 1793744508479 - }, - "emittedAtMs": 1793744508480 - } -] diff --git a/src/main/codex/codex-structured-sleep-activity.test.ts b/src/main/codex/codex-structured-sleep-activity.test.ts deleted file mode 100644 index 3cc920afe1c..00000000000 --- a/src/main/codex/codex-structured-sleep-activity.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { expect, it, vi } from 'vitest' -import sleepFrames from './__fixtures__/codex-app-server-sleep.json' -import { createCodexJournalTranslator } from './structured/journal/codex-structured-journal-translation' - -// Recorded from Codex 0.162.1 app-server calling clock.sleep on 2026-11-03. -it('publishes the requested sleep duration and clears it before the next activity', () => { - const setActivity = vi.fn() - const threadId = sleepFrames[0]!.params.threadId - const turnId = sleepFrames[0]!.params.turnId - const translator = createCodexJournalTranslator({ - sink: { appendItem: () => {}, appendTombstone: () => {}, publish: () => {}, setActivity }, - primaryThreadId: () => threadId - }) - const notify = (method: string, params: unknown) => - translator.handle({ - type: 'notification', - sessionId: 'sleep-session', - threadId, - method, - params - }) - notify('turn/started', { turn: { id: turnId } }) - for (const frame of sleepFrames) { - notify(frame.method, frame.params) - } - expect(setActivity.mock.calls.slice(-2)).toEqual([[{ turnId, text: 'Waiting for 1s' }], [null]]) - notify('item/started', { turnId, item: { id: 'response', type: 'agentMessage', text: '' } }) - expect(setActivity).toHaveBeenLastCalledWith({ turnId, text: 'Drafting a response' }) -}) diff --git a/src/main/ipc/pty/delivery/pty-escape-boundary.test.ts b/src/main/ipc/pty/delivery/pty-escape-boundary.test.ts deleted file mode 100644 index 9da7044c393..00000000000 --- a/src/main/ipc/pty/delivery/pty-escape-boundary.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { afterEach, describe, expect, it } from 'vitest' -import { - _resetPtyEscapeBoundaryForTest, - advanceEscapeBoundary, - advancePtyEscapeBoundary, - markPtyEscapeBoundaryUnknown, - escapeBoundaryFields -} from './pty-escape-boundary' - -afterEach(() => _resetPtyEscapeBoundaryForTest()) - -describe('pty escape boundary', () => { - it('tracks an escape split across payloads', () => { - expect(advancePtyEscapeBoundary('pty', 'a\x1b[4')).toBe('') - expect(advancePtyEscapeBoundary('pty', '2Bb')).toBe('\x1b[') - expect(advancePtyEscapeBoundary('pty', 'c')).toBe('') - }) - - it('stays unknown after a provider gap until an ESC, CAN or SUB resynchronizes it', () => { - markPtyEscapeBoundaryUnknown('pty') - expect(advancePtyEscapeBoundary('pty', '42B text')).toBeNull() - expect(advancePtyEscapeBoundary('pty', 'x\x1b[K')).toBeNull() - expect(advancePtyEscapeBoundary('pty', 'y')).toBe('') - expect(advanceEscapeBoundary(null, 'osc payload\x18text')).toBe('') - }) - - it('marks every start but ground, and says when the boundary is unknown', () => { - expect(escapeBoundaryFields('')).toEqual({}) - expect(escapeBoundaryFields(undefined)).toEqual({}) - expect(escapeBoundaryFields('\x1b[')).toEqual({ midEscape: true }) - expect(escapeBoundaryFields(null)).toEqual({ midEscape: 'unknown' }) - }) - - it('treats a C1 control as an unknown boundary, since xterm parses it and the scanner does not', () => { - // U+009B is an 8-bit CSI introducer: xterm would read `42B` after it as cursor-down. - expect(advanceEscapeBoundary('', 'text\u009b42')).toBeNull() - expect(advanceEscapeBoundary('', 'a\u009bb\x1b[0m')).toBe('') - }) -}) diff --git a/src/main/runtime/hosts/platform-probe/host-machine-probe-parsing.test.ts b/src/main/runtime/hosts/platform-probe/host-machine-probe-parsing.test.ts deleted file mode 100644 index c4fc96e7fc6..00000000000 --- a/src/main/runtime/hosts/platform-probe/host-machine-probe-parsing.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - parseLinuxDmi, - parseMacHardwareProfile, - parseWindowsComputerSystem, - type LinuxDmiFields -} from './host-machine-probe-parsing' - -function macProfile(fields: Record): string { - return JSON.stringify({ SPHardwareDataType: [{ _name: 'hardware_overview', ...fields }] }) -} - -describe('parseMacHardwareProfile', () => { - it('reads the marketing name and treats MacBooks as laptops', () => { - expect( - parseMacHardwareProfile( - macProfile({ machine_name: 'MacBook Pro', machine_model: 'Mac16,5', serial_number: 'X' }) - ) - ).toEqual({ kind: 'laptop', model: 'MacBook Pro' }) - expect( - parseMacHardwareProfile(macProfile({ machine_name: 'Mac mini', machine_model: 'Mac16,10' })) - ).toEqual({ kind: 'desktop', model: 'Mac mini' }) - }) - - it('falls back to the Intel model identifier for the kind when the name is missing', () => { - expect(parseMacHardwareProfile(macProfile({ machine_model: 'MacBookAir9,1' }))).toEqual({ - kind: 'laptop', - model: null - }) - }) - - it('rejects unreadable output', () => { - expect(parseMacHardwareProfile('not json')).toBeNull() - expect(parseMacHardwareProfile('{"SPHardwareDataType":[]}')).toBeNull() - }) -}) - -describe('parseWindowsComputerSystem', () => { - const row = (fields: Record): string => JSON.stringify(fields) - - it('reads mobile PCs as laptops and prefers the family over a Lenovo type code', () => { - expect( - parseWindowsComputerSystem( - row({ - PCSystemType: 2, - Model: '20XWCTO1WW', - Manufacturer: 'LENOVO', - SystemFamily: 'ThinkPad X1 Carbon Gen 9', - ProductType: 1 - }) - ) - ).toEqual({ kind: 'laptop', model: 'ThinkPad X1 Carbon Gen 9' }) - }) - - it('drops firmware placeholders', () => { - expect( - parseWindowsComputerSystem( - row({ - PCSystemType: 1, - Model: 'System Product Name', - Manufacturer: 'System manufacturer', - SystemFamily: 'To Be Filled By O.E.M.', - ProductType: 1 - }) - ) - ).toEqual({ kind: 'desktop', model: null }) - }) - - it('reads Windows Server and virtual machines as servers', () => { - expect( - parseWindowsComputerSystem( - row({ PCSystemType: 1, Model: 'PowerEdge R740', Manufacturer: 'Dell Inc.', ProductType: 3 }) - ) - ).toEqual({ kind: 'server', model: 'PowerEdge R740' }) - expect( - parseWindowsComputerSystem( - row({ PCSystemType: 1, Model: 'Virtual Machine', Manufacturer: 'Microsoft Corporation' }) - ) - ).toEqual({ kind: 'server', model: null }) - }) - - it('rejects unreadable output', () => { - expect(parseWindowsComputerSystem('')).toBeNull() - expect(parseWindowsComputerSystem('[1]')).toBeNull() - }) -}) - -describe('parseLinuxDmi', () => { - const dmi = (fields: Partial): LinuxDmiFields => ({ - chassisType: null, - productName: null, - productFamily: null, - sysVendor: null, - ...fields - }) - - it('maps chassis types to laptop, desktop and server', () => { - expect(parseLinuxDmi(dmi({ chassisType: '10', productName: 'XPS 13 9310' }))).toEqual({ - kind: 'laptop', - model: 'XPS 13 9310' - }) - expect(parseLinuxDmi(dmi({ chassisType: '3', productName: 'Default string' }))).toEqual({ - kind: 'desktop', - model: null - }) - expect(parseLinuxDmi(dmi({ chassisType: '23', productName: 'ProLiant DL380 Gen10' }))).toEqual({ - kind: 'server', - model: 'ProLiant DL380 Gen10' - }) - }) - - it('reads missing DMI and virtual machines as servers without a model', () => { - expect(parseLinuxDmi(dmi({}))).toEqual({ kind: 'server', model: null }) - expect( - parseLinuxDmi( - dmi({ chassisType: '1', productName: 'Standard PC (Q35 + ICH9, 2009)', sysVendor: 'QEMU' }) - ) - ).toEqual({ kind: 'server', model: null }) - expect( - parseLinuxDmi( - dmi({ - chassisType: '3', - productName: 'Virtual Machine', - sysVendor: 'Microsoft Corporation' - }) - ) - ).toEqual({ kind: 'server', model: null }) - }) -}) diff --git a/src/main/runtime/rpc/methods/orchestration/messaging/finished-worker-mail.test.ts b/src/main/runtime/rpc/methods/orchestration/messaging/finished-worker-mail.test.ts index b2bcc19bd34..806100c79fc 100644 --- a/src/main/runtime/rpc/methods/orchestration/messaging/finished-worker-mail.test.ts +++ b/src/main/runtime/rpc/methods/orchestration/messaging/finished-worker-mail.test.ts @@ -99,52 +99,6 @@ describe('a worker after its worker_done', () => { ).rejects.toMatchObject({ code: 'run_required' }) }) - it('resumes its own question after a follow-up starts on the same worker', async () => { - const { db, runtime, ctx } = harness.setup() - const task = db.createTask({ spec: 'work' }) - const dispatch = createRootDispatch(db, task.id, 'term_worker', 'tab_worker:leaf_worker') - vi.mocked(runtime.getTerminalPaneKey).mockImplementation((handle) => - handle === 'term_worker' - ? 'tab_worker:leaf_worker' - : handle === 'term_coord' - ? harness.coordinatorPaneKey - : null - ) - await harness.call( - 'orchestration.send', - { - from: 'term_worker', - type: 'worker_done', - subject: 'Done', - payload: JSON.stringify({ taskId: task.id, dispatchId: dispatch.id, outcome: 'succeeded' }) - }, - ctx - ) - const asked = await harness.call( - 'orchestration.ask', - { from: 'term_worker', question: 'Anything else?', timeoutMs: 1 }, - ctx - ) - expect(asked).toMatchObject({ timedOut: true }) - const questionId = - asked && typeof asked === 'object' && 'messageId' in asked ? asked.messageId : '' - createRootDispatch( - db, - db.createTask({ spec: 'more' }).id, - 'term_worker', - 'tab_worker:leaf_worker' - ) - await harness.call( - 'orchestration.reply', - { from: 'term_coord', id: questionId, body: 'Nothing else.' }, - ctx - ) - - await expect( - harness.call('orchestration.ask', { from: 'term_worker', resume: questionId }, ctx) - ).resolves.toMatchObject({ answer: 'Nothing else.' }) - }) - it('tells a finished worker on a paired host that its coordinator is out of reach', async () => { const { db, runtime, ctx } = harness.setup(false) db.createRemoteDispatchAttachment({ diff --git a/src/renderer/src/hooks/use-pr-check-refresh-owner.test.ts b/src/renderer/src/hooks/use-pr-check-refresh-owner.test.ts deleted file mode 100644 index 793bcab7dc5..00000000000 --- a/src/renderer/src/hooks/use-pr-check-refresh-owner.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -// @vitest-environment happy-dom -import { act, cleanup, renderHook } from '@testing-library/react' -import { afterEach, expect, it } from 'vitest' -import { usePRCheckRefreshOwner } from './use-pr-check-refresh-owner' -import { acceptPRCheckObservation } from '../../../shared/github/complete-pr-check-owner' -import type { GitHubWorkItem } from '../../../shared/github/work-item-types' -afterEach(cleanup) -const item: GitHubWorkItem = { - id: 'pr42', - repoId: 'repo', - number: 42, - type: 'pr', - url: 'https://github.com/acme/widgets/pull/42', - title: 'PR', - state: 'open', - headSha: 'h1', - updatedAt: '', - labels: [], - author: null -} -const summary = { - state: 'failure' as const, - total: 101, - passed: 100, - failed: 1, - pending: 0, - neutral: 0 -} -const context = { scope: 'source:r1', complete: true, current: true } -it('retains a refreshed head across parent allocation and sequential refresh, then honors a newer parent observation', () => { - const view = renderHook(({ parent }) => usePRCheckRefreshOwner(parent), { - initialProps: { parent: item } - }) - act(() => - view.result.current.onOwnerUpdated( - acceptPRCheckObservation({ ...item, headSha: 'h2', checksSummary: summary }, null, context)! - ) - ) - view.rerender({ parent: { ...item } }) - expect(view.result.current.checkOwner.headSha).toBe('h2') - act(() => - view.result.current.onOwnerUpdated( - acceptPRCheckObservation( - { ...view.result.current.checkOwner, checksSummary: undefined }, - null, - context - )! - ) - ) - expect(view.result.current.checkOwner.checksSummary).toEqual(summary) - const newer = acceptPRCheckObservation( - { - ...item, - headSha: 'h2', - checksSummary: { ...summary, state: 'success', failed: 0, passed: 101 } - }, - null, - context - )! - view.rerender({ parent: newer }) - expect(view.result.current.checkOwner.checksSummary?.state).toBe('success') -}) -it('does not reuse last-good after the producing runtime changes', () => { - const view = renderHook(() => usePRCheckRefreshOwner(item)) - act(() => - view.result.current.onOwnerUpdated( - acceptPRCheckObservation({ ...item, checksSummary: summary }, null, context)! - ) - ) - act(() => - view.result.current.onOwnerUpdated( - acceptPRCheckObservation(item, null, { ...context, scope: 'source:r2' })! - ) - ) - expect(view.result.current.checkOwner.checksSummary).toBeUndefined() -}) diff --git a/src/renderer/src/runtime/local-runtime-capabilities.test.ts b/src/renderer/src/runtime/local-runtime-capabilities.test.ts deleted file mode 100644 index 6e1c263c4c8..00000000000 --- a/src/renderer/src/runtime/local-runtime-capabilities.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { afterEach, expect, it, vi } from 'vitest' -import { - refreshLocalRuntimeCapabilities, - readLocalRuntimeCapabilitiesOrUnknown, - setLocalRuntimeCapabilitiesForTests -} from './local-runtime-capabilities' -import { GITHUB_COMPLETE_PR_CHECK_OBSERVATION_CAPABILITY as complete } from '../../../shared/source-control/runtime/source-control-runtime-capabilities' -afterEach(() => { - setLocalRuntimeCapabilitiesForTests(null) - vi.unstubAllGlobals() -}) -it('keeps a declared local capability across transient probe failure and retries an initially unknown probe', async () => { - const getStatus = vi.fn().mockRejectedValue(new Error('temporary')) - vi.stubGlobal('window', { api: { runtime: { getStatus } } }) - setLocalRuntimeCapabilitiesForTests([complete]) - expect(await refreshLocalRuntimeCapabilities()).toEqual([complete]) - expect(readLocalRuntimeCapabilitiesOrUnknown()).toEqual([complete]) - setLocalRuntimeCapabilitiesForTests(null) - expect(await refreshLocalRuntimeCapabilities()).toEqual([]) - expect(readLocalRuntimeCapabilitiesOrUnknown()).toBeNull() - getStatus.mockResolvedValueOnce({ capabilities: [complete] }) - expect(await refreshLocalRuntimeCapabilities()).toEqual([complete]) -}) diff --git a/src/renderer/src/store/slices/workspace-cleanup-restore.test.ts b/src/renderer/src/store/slices/workspace-cleanup-restore.test.ts deleted file mode 100644 index e37bd093c03..00000000000 --- a/src/renderer/src/store/slices/workspace-cleanup-restore.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { WORKSPACE_CLEANUP_CLASSIFIER_VERSION } from '../../../../shared/workspace-cleanup/workspace-cleanup' -import { - NOW, - WORKTREE_ID, - createCleanupTestStore, - installWorkspaceCleanupApi, - makeCandidate -} from './workspace-cleanup-slice-test-harness' - -const LEGACY_DISMISSAL = { - worktreeId: WORKTREE_ID, - dismissedAt: NOW, - fingerprint: 'fingerprint-1', - classifierVersion: WORKSPACE_CLEANUP_CLASSIFIER_VERSION -} - -function seedLegacyDismissalOnTwoHosts() { - installWorkspaceCleanupApi(vi.fn()) - const store = createCleanupTestStore() - const local = makeCandidate({ blockers: ['dismissed'] }) - const ssh = makeCandidate({ - executionHostId: 'ssh:ssh-1', - connectionId: 'ssh-1', - blockers: ['dismissed'] - }) - store.setState({ - workspaceCleanupDismissals: { [WORKTREE_ID]: LEGACY_DISMISSAL }, - workspaceCleanupScan: { scannedAt: NOW, candidates: [local, ssh], errors: [] } - }) - return { store, local } -} - -function dismissedByHost(store: ReturnType) { - return Object.fromEntries( - (store.getState().workspaceCleanupScan?.candidates ?? []).map((candidate) => [ - candidate.executionHostId, - candidate.blockers.includes('dismissed') - ]) - ) -} - -describe('restoreWorkspaceCleanupCandidates', () => { - it('keeps a legacy dismissal on the other host when one host stops ignoring', async () => { - const { store, local } = seedLegacyDismissalOnTwoHosts() - - await store.getState().restoreWorkspaceCleanupCandidates([local]) - - expect(window.api.workspaceCleanup.dismiss).toHaveBeenCalledWith({ - dismissals: [{ ...LEGACY_DISMISSAL, executionHostId: 'ssh:ssh-1' }], - restoredDismissalKeys: [`local\0${WORKTREE_ID}`, WORKTREE_ID] - }) - expect(Object.keys(store.getState().workspaceCleanupDismissals)).toEqual([ - `ssh:ssh-1\0${WORKTREE_ID}` - ]) - expect(dismissedByHost(store)).toEqual({ local: false, 'ssh:ssh-1': true }) - }) - - it('leaves the row ignored when the dismissal store rejects', async () => { - const { store, local } = seedLegacyDismissalOnTwoHosts() - vi.mocked(window.api.workspaceCleanup.dismiss).mockRejectedValueOnce(new Error('disk full')) - - await expect(store.getState().restoreWorkspaceCleanupCandidates([local])).rejects.toThrow( - 'disk full' - ) - - expect(Object.keys(store.getState().workspaceCleanupDismissals)).toEqual([WORKTREE_ID]) - expect(dismissedByHost(store)).toEqual({ local: true, 'ssh:ssh-1': true }) - }) -}) diff --git a/src/shared/native-chat/tools/native-chat-edit-summary.performance.test.ts b/src/shared/native-chat/tools/native-chat-edit-summary.performance.test.ts deleted file mode 100644 index 5729758d191..00000000000 --- a/src/shared/native-chat/tools/native-chat-edit-summary.performance.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { NativeChatMessage } from '../native-chat-types' -import { nativeChatTurnDiffs, sameNativeChatTurnDiff } from './native-chat-turn-diffs' - -// Count source normalization separately from rendered patches: unopened summaries still consume input. -describe('landed edit summary work', () => { - it.each([100, 1000])('normalizes %i Claude edits once and only new input on append', (count) => { - let contentReads = 0 - const edit = (index: number): NativeChatMessage => ({ - id: `edit-${index}`, - role: 'assistant', - source: 'transcript', - timestamp: index, - blocks: [ - { - type: 'tool-call', - name: 'Edit', - state: 'completed', - input: { - file_path: `/repo/file-${index}.ts`, - old_string: 'old-line\n'.repeat(40), - get new_string() { - contentReads += 1 - return 'new-line\n'.repeat(40) - } - } - }, - { type: 'tool-result', output: 'The file was updated successfully.' } - ] - }) - const messages = Array.from({ length: count }, (_, index) => edit(index)) - const keys = messages.map(() => 'u') - const first = nativeChatTurnDiffs(messages, keys).get('u')! - expect(first.files).toHaveLength(count) - const coldReads = contentReads - expect(coldReads).toBeGreaterThanOrEqual(count) - expect(coldReads).toBeLessThanOrEqual(count * 4) - const same = nativeChatTurnDiffs([...messages], [...keys]).get('u')! - expect(contentReads).toBe(coldReads) - expect(sameNativeChatTurnDiff(first, same)).toBe(true) - const appended = nativeChatTurnDiffs([...messages, edit(count)], [...keys, 'u']).get('u')! - expect(appended.files).toHaveLength(count + 1) - expect(contentReads - coldReads).toBe(coldReads / count) - expect(sameNativeChatTurnDiff(first, appended)).toBe(false) - const refreshed = [...messages] - const last = refreshed[count - 1]! - refreshed[count - 1] = { - ...last, - blocks: [last.blocks[0]!, { type: 'tool-result', output: 'Updated successfully.' }] - } - const beforeResult = contentReads - nativeChatTurnDiffs(refreshed, keys) - expect(contentReads - beforeResult).toBe(coldReads / count) - }) -}) diff --git a/src/shared/sidebar-list/imported-worktree-lines.test.ts b/src/shared/sidebar-list/imported-worktree-lines.test.ts deleted file mode 100644 index ca50093ceb6..00000000000 --- a/src/shared/sidebar-list/imported-worktree-lines.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { Repo } from '../repo-types' -import type { DetectedWorktree } from '../worktree/types' -import { appendImportedWorktreeLines } from './imported-worktree-lines' -import type { ImportedWorktreesCardCandidate, Row } from './row-types' - -const local: Repo = { - id: 'repo-a', - displayName: 'alpha', - path: '/a', - badgeColor: '#000', - addedAt: 0 -} -const localTwo: Repo = { ...local, id: 'repo-b', displayName: 'beta', path: '/b' } -const remote: Repo = { ...local, id: 'repo-c', path: '/c', executionHostId: 'runtime:env-1' } - -function candidate(repo: Repo): ImportedWorktreesCardCandidate { - const hidden: DetectedWorktree = { - id: `hidden-${repo.id}`, - repoId: repo.id, - path: `/wt/${repo.id}`, - branch: 'refs/heads/hidden', - head: 'abc123', - isBare: false, - isMainWorktree: false, - linkedIssue: null, - linkedPR: null, - linkedLinearIssue: null, - isArchived: false, - comment: '', - isUnread: false, - isPinned: false, - displayName: 'hidden', - sortOrder: 0, - lastActivityAt: 0, - visible: false, - selectedCheckout: false, - ownership: 'external' - } - return { repo, hiddenWorktrees: [hidden] } -} - -function append(repos: Repo[]): Row[] { - return appendImportedWorktreeLines([], { - importedWorktreesByRepo: new Map(repos.map((repo) => [repo.id, candidate(repo)])), - defaultHostId: 'local', - hostLabelById: new Map([['runtime:env-1', 'Build box']]) - }) -} - -describe('appendImportedWorktreeLines', () => { - it('covers every project on a host with one unlabelled line', () => { - expect(append([local, localTwo])).toMatchObject([ - { - placement: 'all-projects', - hostId: 'local', - projects: [{ repo: { id: 'repo-a' } }, { repo: { id: 'repo-b' } }] - } - ]) - expect(append([local, localTwo])[0]).not.toHaveProperty('hostContextLabel') - }) - - it('gives each host its own line, named, when projects span hosts', () => { - expect(append([local, remote])).toMatchObject([ - { hostId: 'local', hostContextHostId: 'local', projects: [{ repo: { id: 'repo-a' } }] }, - { - hostId: 'runtime:env-1', - hostContextLabel: 'Build box', - projects: [{ repo: { id: 'repo-c' } }] - } - ]) - }) -}) diff --git a/src/shared/source-control/ai/settings/source-control-ai-discovered-models.test.ts b/src/shared/source-control/ai/settings/source-control-ai-discovered-models.test.ts deleted file mode 100644 index ba735b2e86a..00000000000 --- a/src/shared/source-control/ai/settings/source-control-ai-discovered-models.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { expect, it } from 'vitest' -import { LOCAL_COMMIT_MESSAGE_HOST_KEY } from '../generation/commit-message-host-key' -import { savedDiscoveredModels, withDiscoveredModels } from './source-control-ai-model-selection' -import { normalizeSourceControlAiSettings } from './source-control-ai-settings' - -it('saves discovered Claude rows without the resolved model an alias row carries', () => { - const discovered = [ - { id: 'claude-opus-5-5', label: 'Claude Opus 5.5', resolvedModel: 'claude-opus-5-5' }, - { id: 'opus', label: 'Opus alias', resolvedModel: 'claude-opus-5-5' } - ] - const saved = withDiscoveredModels( - normalizeSourceControlAiSettings(undefined), - 'claude', - discovered, - LOCAL_COMMIT_MESSAGE_HOST_KEY - ) - const rows = [ - { id: 'claude-opus-5-5', label: 'Claude Opus 5.5' }, - { id: 'opus', label: 'Opus alias' } - ] - expect(saved.discoveredModelsByAgent?.claude).toEqual(rows) - expect(saved.discoveredModelsByAgentByHost?.[LOCAL_COMMIT_MESSAGE_HOST_KEY]?.claude).toEqual(rows) - // The refresh compares the same saved shape, so an unchanged listing writes nothing. - expect(savedDiscoveredModels(discovered)).toEqual(rows) -}) diff --git a/tests/e2e/combined-diff-syntax-colour.spec.ts b/tests/e2e/combined-diff-syntax-colour.spec.ts deleted file mode 100644 index 20b938af3b8..00000000000 --- a/tests/e2e/combined-diff-syntax-colour.spec.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { execFileSync } from 'node:child_process' -import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs' -import os from 'node:os' -import path from 'node:path' -import type { Page } from '@stablyai/playwright-test' -import { test, expect } from './helpers/orca-app' -import { waitForSessionReady } from './helpers/store' - -const FILE_COUNT = 8 - -declare global { - var __colouredWhenLaidOut: Record | undefined -} - -function runGit(repoPath: string, args: string[]): void { - execFileSync('git', args, { cwd: repoPath, stdio: 'pipe' }) -} - -function createRepo(): string { - const repoPath = realpathSync(mkdtempSync(path.join(os.tmpdir(), 'orca-diff-colour-'))) - runGit(repoPath, ['init']) - runGit(repoPath, ['config', 'user.email', 'e2e@test.local']) - runGit(repoPath, ['config', 'user.name', 'E2E Test']) - mkdirSync(path.join(repoPath, 'src'), { recursive: true }) - const file = (index: number): string => path.join(repoPath, 'src', `colour-${index}.ts`) - for (let index = 0; index < FILE_COUNT; index += 1) { - writeFileSync(file(index), `export const base${index} = ${index}\n`) - } - runGit(repoPath, ['add', '-A']) - runGit(repoPath, ['commit', '-m', 'base']) - for (let index = 0; index < FILE_COUNT; index += 1) { - const added = Array.from( - { length: 40 }, - (_, line) => `export function changed${index}_${line}(): string { return 'v${line}' }` - ).join('\n') - writeFileSync(file(index), `export const base${index} = ${index}\n${added}\n`) - } - return repoPath -} - -async function openCombinedDiff(page: Page, repoPath: string): Promise { - const repoId = await page.evaluate(async (p) => { - const repo = await window.__store!.getState().addRepoPath(p) - if (!repo) { - throw new Error('repo not added') - } - return repo.id - }, repoPath) - await expect - .poll(() => - page.evaluate(async (id) => { - const store = window.__store! - await store.getState().fetchWorktrees(id) - return store.getState().worktreesByRepo[id]?.length ?? 0 - }, repoId) - ) - .toBeGreaterThan(0) - await page.evaluate( - async ({ id, p }) => { - const store = window.__store! - const state = store.getState() - const worktree = state.worktreesByRepo[id]!.find((w) => w.path === p)! - state.setActiveRepo(id) - state.setActiveWorktree(worktree.id) - const status = await window.api.git.status({ worktreePath: p }) - const entries = status.entries.filter((entry) => entry.area === 'unstaged') - state.setGitStatus(worktree.id, status) - state.openAllDiffs(worktree.id, p, undefined, 'unstaged', entries) - }, - { id: repoId, p: repoPath } - ) -} - -test.describe('Combined diff syntax colour', () => { - test.use({ seedTestRepo: false }) - - test('a section scrolled into view already has syntax colours when its lines are laid out', async ({ - orcaPage - }) => { - await waitForSessionReady(orcaPage) - const repoPath = createRepo() - try { - await openCombinedDiff(orcaPage, repoPath) - // Monaco loads a language's tokenizer on first use; start once the first section is coloured. - await expect - .poll(() => - orcaPage.evaluate(() => - [...document.querySelectorAll('.combined-diff-scroll-container .view-line')].some( - (line) => - new Set( - [...line.querySelectorAll('span span')] - // Bracket-pair colours appear without syntax tokens. - .filter((t) => !/^[(){}]$/.test(t.textContent ?? '')) - .map((t) => getComputedStyle(t).color) - ).size > 1 - ) - ) - ) - .toBe(true) - - await orcaPage.evaluate(() => { - const seen: Record = {} - globalThis.__colouredWhenLaidOut = seen - // Record each section once, at the first DOM mutation where its first added line exists. - new MutationObserver(() => { - for (const row of document.querySelectorAll( - '[data-combined-diff-section-row]' - )) { - const key = row.dataset.combinedDiffSectionKey ?? '' - const line = [...row.querySelectorAll('.editor.modified .view-line')].find( - (candidate) => candidate.textContent?.startsWith('export\u00a0function') - ) - if (key in seen || !line) { - continue - } - const colours = new Set( - [...line.querySelectorAll('span span')] - // Bracket-pair colours appear without syntax tokens. - .filter((t) => !/^[(){}]$/.test(t.textContent ?? '')) - .map((t) => getComputedStyle(t).color) - ) - seen[key] = colours.size > 1 - } - }).observe(document.body, { childList: true, subtree: true }) - }) - await expect - .poll( - () => - orcaPage.evaluate(() => { - const container = document.querySelector( - '.combined-diff-scroll-container' - )! - container.scrollTop += 400 - return Object.keys(globalThis.__colouredWhenLaidOut ?? {}).length - }), - { intervals: [50], timeout: 15_000 } - ) - .toBe(FILE_COUNT) - const coloured = await orcaPage.evaluate(() => globalThis.__colouredWhenLaidOut) - expect(Object.entries(coloured ?? {}).filter(([, value]) => !value)).toEqual([]) - } finally { - rmSync(repoPath, { recursive: true, force: true }) - } - }) -})