diff --git a/config/scripts/ci-shard-timings.json b/config/scripts/ci-shard-timings.json index 8a68b85284b..f077f3eaca0 100644 --- a/config/scripts/ci-shard-timings.json +++ b/config/scripts/ci-shard-timings.json @@ -7371,7 +7371,6 @@ "src/renderer/src/components/dashboard-popout/use-agent-dashboard-telemetry.test.ts": 1675, "src/renderer/src/components/dashboard-popout/useDashboardSnapshot.test.tsx": 432, "src/renderer/src/components/dashboard/AgentDashboardDrawer.test.tsx": 1745, - "src/renderer/src/components/dashboard/AgentDashboardSettingsMenu.test.tsx": 479, "src/renderer/src/components/dashboard/DashboardAgentChildDisclosure.test.tsx": 1607, "src/renderer/src/components/dashboard/DashboardAgentRow.test.tsx": 1601, "src/renderer/src/components/dashboard/agent-dashboard-open-mode.test.ts": 43, @@ -8755,7 +8754,6 @@ "src/renderer/src/components/settings/FloatingWorkspacePane.test.tsx": 1311, "src/renderer/src/components/settings/GeneralPane.section-lifetime.test.tsx": 1192, "src/renderer/src/components/settings/GeneralPane.test.ts": 1066, - "src/renderer/src/components/settings/GeneralRemoteServerUpdates.test.tsx": 283, "src/renderer/src/components/settings/GeneralUpdateSettingsSection.test.tsx": 1749, "src/renderer/src/components/settings/GeneralWorkspaceSettingsSection.test.tsx": 2551, "src/renderer/src/components/settings/GhosttyImportModal.test.ts": 162, @@ -8844,7 +8842,6 @@ "src/renderer/src/components/settings/TerminalSettingsPreview.lifecycle.test.tsx": 318, "src/renderer/src/components/settings/TerminalTccAttributionNotice.test.tsx": 282, "src/renderer/src/components/settings/TerminalThemeSections.lifecycle.test.ts": 1337, - "src/renderer/src/components/settings/VoiceDictationSettingsSection.test.tsx": 491, "src/renderer/src/components/settings/VoiceMicrophoneSetting.test.tsx": 577, "src/renderer/src/components/settings/VoicePane.test.tsx": 770, "src/renderer/src/components/settings/VoiceSpeechModelSection.test.tsx": 647, @@ -8898,7 +8895,6 @@ "src/renderer/src/components/settings/repository/execution/RepositoryHostSetupsSection.test.tsx": 1674, "src/renderer/src/components/settings/repository/execution/RepositoryHostSetupsSection.workspace-window.test.tsx": 1584, "src/renderer/src/components/settings/repository/execution/RepositoryWorktreeDefaultsSection.test.tsx": 577, - "src/renderer/src/components/settings/repository/execution/repository-description-templates.test.tsx": 592, "src/renderer/src/components/settings/repository/execution/repository-hook-settings-draft.test.ts": 368, "src/renderer/src/components/settings/repository/execution/repository-host-setup-options.test.ts": 151, "src/renderer/src/components/settings/repository/identity/RepositoryForkSyncSection.test.tsx": 530, @@ -9180,7 +9176,6 @@ "src/renderer/src/components/sidebar/use-workspace-reveal-body-redirect.test.tsx": 142, "src/renderer/src/components/sidebar/use-workspace-status-drop.test.ts": 158, "src/renderer/src/components/sidebar/use-worktree-activity-status.test.tsx": 133, - "src/renderer/src/components/sidebar/use-worktree-activity-statuses.test.ts": 123, "src/renderer/src/components/sidebar/use-worktree-agent-rows-subscriptions.test.tsx": 1600, "src/renderer/src/components/sidebar/use-worktree-card-secondary-details.store-subscriptions.test.tsx": 1528, "src/renderer/src/components/sidebar/use-worktree-sleep-state.test.tsx": 285, @@ -9458,7 +9453,6 @@ "src/renderer/src/components/status-bar/workspace-space-layout.test.ts": 21, "src/renderer/src/components/status-bar/workspace-space-open-change.test.ts": 123, "src/renderer/src/components/status-bar/workspace-space-presentation.test.ts": 522, - "src/renderer/src/components/status-bar/workspace-space-treemap.test.tsx": 389, "src/renderer/src/components/status-bar/workspace-space-visit-activity.test.ts": 86, "src/renderer/src/components/status-bar/workspace-space-worktree-row.test.tsx": 2100, "src/renderer/src/components/tab-bar/BrowserTab.test.tsx": 1689, @@ -9958,7 +9952,6 @@ "src/renderer/src/components/terminal-pane/terminal-copy-shortcut.test.ts": 1636, "src/renderer/src/components/terminal-pane/terminal-ctrl-enter.test.ts": 115, "src/renderer/src/components/terminal-pane/terminal-cursor-appearance-precedence.test.ts": 303, - "src/renderer/src/components/terminal-pane/terminal-cursor-inactive-style.test.ts": 388, "src/renderer/src/components/terminal-pane/terminal-dead-session-reconcile.test.ts": 34, "src/renderer/src/components/terminal-pane/terminal-delivery-watchdog.test.ts": 140, "src/renderer/src/components/terminal-pane/terminal-drop-handler.test.ts": 519, @@ -10185,7 +10178,6 @@ "src/renderer/src/components/terminal-pane/use-mobile-overlay-ticks-desktop-fit.test.tsx": 229, "src/renderer/src/components/terminal-pane/use-mobile-overlay-ticks.perf.test.tsx": 237, "src/renderer/src/components/terminal-pane/use-notification-dispatch-hidden-workspace.test.ts": 453, - "src/renderer/src/components/terminal-pane/use-notification-dispatch-verdict.test.ts": 424, "src/renderer/src/components/terminal-pane/use-notification-dispatch.test.ts": 432, "src/renderer/src/components/terminal-pane/use-parked-terminal-watcher-synchronization.react185.test.tsx": 298, "src/renderer/src/components/terminal-pane/use-system-prefers-dark.test.ts": 33, @@ -10311,7 +10303,6 @@ "src/renderer/src/components/workspace-cleanup/workspace-cleanup-removal-settlement.test.ts": 106, "src/renderer/src/components/workspace-cleanup/workspace-cleanup-removal-timeout-recovery.test.ts": 1279, "src/renderer/src/components/workspace-cleanup/workspace-cleanup-sort-header.test.tsx": 598, - "src/renderer/src/components/workspace-emoji/WorkspaceEmojiSuggestionPopover.test.tsx": 332, "src/renderer/src/components/workspace-emoji/useWorkspaceEmojiShortcodeInput.test.tsx": 236, "src/renderer/src/components/workspace-space/SpaceWindowStatePublisher.test.tsx": 618, "src/renderer/src/components/workspace-space/space-window-state.test.ts": 162, @@ -10529,7 +10520,6 @@ "src/renderer/src/hooks/worktree-head-identity-apply.test.ts": 50, "src/renderer/src/hooks/zoom-routing.test.ts": 594, "src/renderer/src/i18n/I18nProvider.test.tsx": 1691, - "src/renderer/src/i18n/catalog-nested-settings.test.ts": 777, "src/renderer/src/i18n/intl-locale.test.ts": 135, "src/renderer/src/i18n/language-catalog-timeout.test.tsx": 1932, "src/renderer/src/i18n/language-detection-reconciliation.test.tsx": 1619, diff --git a/src/cli/handlers/connector-reply.test.ts b/src/cli/handlers/connector-reply.test.ts deleted file mode 100644 index 83671b68ebf..00000000000 --- a/src/cli/handlers/connector-reply.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import type { HandlerContext } from '../dispatch' -import { RuntimeClientError, type RuntimeClient } from '../runtime-client' -import { CONNECTOR_REPLY_UNAVAILABLE } from '../../shared/rpc-contract/connector-params' -import { CONNECTOR_HANDLERS, formatReply } from './connector' - -const call = vi.fn() -// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the reply handler calls only client.call. -const client = { call } as unknown as RuntimeClient - -function context(): HandlerContext { - return { client, cwd: process.cwd(), flags: new Map([['text', 'done']]), json: true, rawArgs: [] } -} - -beforeEach(() => { - vi.stubEnv('ORCA_PANE_KEY', 'tab:1') - vi.spyOn(console, 'log').mockImplementation(() => {}) - call.mockReset() -}) - -afterEach(() => { - vi.unstubAllEnvs() - vi.restoreAllMocks() -}) - -describe('orca connector reply', () => { - it('sends the calling pane and the text, and says where it went', async () => { - call.mockResolvedValue({ result: { status: 'posted', messageId: '1793.1' } }) - await CONNECTOR_HANDLERS['connector reply'](context()) - expect(call).toHaveBeenCalledWith( - 'connector.reply', - { paneKey: 'tab:1', replyId: expect.any(String), text: 'done' }, - { timeoutMs: 180_000 } - ) - expect(formatReply({ status: 'posted' })).toBe('Posted to the thread.') - expect(formatReply({ status: 'queued' })).toBe('Sent; Orca Cloud will post it to the thread.') - }) - - it('takes the pane from the scrub-safe alias when Claude scrubbed ORCA_PANE_KEY', async () => { - vi.stubEnv('ORCA_PANE_KEY', '') - vi.stubEnv('ORCA_AGENT_PANE', 'tab:2') - call.mockResolvedValue({ result: { status: 'queued' } }) - await CONNECTOR_HANDLERS['connector reply'](context()) - expect(call.mock.calls[0]?.[1]).toMatchObject({ paneKey: 'tab:2' }) - }) - - it.each([ - 'not_a_cloud_conversation', - 'connector_not_connected', - 'connectors_disabled', - 'method_not_found' - ])('says replies are not available from this host when the host answers %s', async (code) => { - call.mockRejectedValue(new RuntimeClientError(code, code)) - await expect(CONNECTOR_HANDLERS['connector reply'](context())).rejects.toMatchObject({ - code: 'not_a_cloud_conversation', - message: CONNECTOR_REPLY_UNAVAILABLE - }) - }) - - it('passes a refusal through, and refuses outside an agent pane', async () => { - call.mockRejectedValue(new RuntimeClientError('no_current_turn', 'no_current_turn')) - await expect(CONNECTOR_HANDLERS['connector reply'](context())).rejects.toMatchObject({ - code: 'no_current_turn' - }) - expect(call).toHaveBeenCalledTimes(1) - - vi.stubEnv('ORCA_PANE_KEY', '') - vi.stubEnv('ORCA_AGENT_PANE', '') - await expect(CONNECTOR_HANDLERS['connector reply'](context())).rejects.toMatchObject({ - code: 'invalid_argument' - }) - }) -}) diff --git a/src/cli/runtime/serve-agent-browser-driver.test.ts b/src/cli/runtime/serve-agent-browser-driver.test.ts index 8dbd83e0816..dc9b5970f60 100644 --- a/src/cli/runtime/serve-agent-browser-driver.test.ts +++ b/src/cli/runtime/serve-agent-browser-driver.test.ts @@ -2,7 +2,7 @@ import { mkdirSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from 'node import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' -import { findAppAgentBrowserDriver, stageAppAgentBrowserDriver } from './serve-agent-browser-driver' +import { stageAppAgentBrowserDriver } from './serve-agent-browser-driver' const roots: string[] = [] afterEach(() => { @@ -12,23 +12,6 @@ afterEach(() => { }) describe("finding the app's agent-browser driver (#33846)", () => { - it.each([ - ['linux', 'x64', 'agent-browser-linux-x64'], - ['darwin', 'arm64', 'agent-browser-darwin-arm64'], - ['win32', 'x64', 'agent-browser-win32-x64.exe'] - ] as const)('finds the copy a packaged %s app ships in resources', (platform, arch, name) => { - const resources = mkdtempSync(join(tmpdir(), 'orca-serve-agent-browser-')) - roots.push(resources) - mkdirSync(join(resources, 'app.asar.unpacked')) - writeFileSync(join(resources, name), '') - expect(findAppAgentBrowserDriver(join(resources, 'app.asar.unpacked'), platform, arch)).toBe( - join(resources, name) - ) - expect(findAppAgentBrowserDriver(join(resources, 'app.asar.unpacked'), platform, 'ia32')).toBe( - undefined - ) - }) - // A running daemon locks its image on Windows; lending the installed copy would block app updates. it('hands Windows orcad a profile copy outside the app install', async () => { const resources = mkdtempSync(join(tmpdir(), 'orca-serve-agent-browser-')) diff --git a/src/renderer/src/components/dashboard/AgentDashboardSettingsMenu.test.tsx b/src/renderer/src/components/dashboard/AgentDashboardSettingsMenu.test.tsx deleted file mode 100644 index c8445800013..00000000000 --- a/src/renderer/src/components/dashboard/AgentDashboardSettingsMenu.test.tsx +++ /dev/null @@ -1,71 +0,0 @@ -// @vitest-environment happy-dom -import { act, type ReactNode } from 'react' -import { createRoot, type Root } from 'react-dom/client' -import { afterEach, describe, expect, it, vi } from 'vitest' - -const updateSettings = vi.fn() - -vi.mock('@/store', () => ({ - useAppStore: ( - selector: (state: { - settings: { - experimentalAgentDashboardMode: 'in-window' - experimentalAgentDashboardShowIdle: boolean - } - updateSettings: typeof updateSettings - }) => unknown - ) => - selector({ - settings: { - experimentalAgentDashboardMode: 'in-window', - experimentalAgentDashboardShowIdle: false - }, - updateSettings - }) -})) - -vi.mock('@/components/ui/dropdown-menu', () => ({ - DropdownMenu: ({ children }: { children: ReactNode }) => <>{children}, - DropdownMenuContent: ({ children }: { children: ReactNode }) =>
{children}
, - DropdownMenuSeparator: () =>
, - DropdownMenuTrigger: ({ children }: { children: ReactNode }) => <>{children} -})) - -vi.mock('@/components/ui/tooltip', () => ({ - Tooltip: ({ children }: { children: ReactNode }) => <>{children}, - TooltipContent: ({ children }: { children: ReactNode }) => {children}, - TooltipTrigger: ({ children }: { children: ReactNode }) => <>{children} -})) - -import { AgentDashboardSettingsMenu } from './AgentDashboardSettingsMenu' - -let root: Root | null = null -let container: HTMLDivElement | null = null - -afterEach(() => { - act(() => root?.unmount()) - root = null - container?.remove() - container = null - updateSettings.mockReset() -}) - -describe('AgentDashboardSettingsMenu', () => { - it('owns the idle-agent visibility setting', () => { - container = document.createElement('div') - document.body.appendChild(container) - root = createRoot(container) - act(() => { - root?.render() - }) - - const toggle = container.querySelector( - 'button[role="switch"][aria-label="Show idle agents"]' - ) - expect(toggle).not.toBeNull() - - act(() => toggle?.click()) - - expect(updateSettings).toHaveBeenCalledWith({ experimentalAgentDashboardShowIdle: true }) - }) -}) diff --git a/src/renderer/src/components/settings/GeneralRemoteServerUpdates.test.tsx b/src/renderer/src/components/settings/GeneralRemoteServerUpdates.test.tsx deleted file mode 100644 index a283ef30af5..00000000000 --- a/src/renderer/src/components/settings/GeneralRemoteServerUpdates.test.tsx +++ /dev/null @@ -1,61 +0,0 @@ -// @vitest-environment happy-dom - -import { act } from 'react' -import { createRoot } from 'react-dom/client' -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { GeneralRemoteServerUpdates } from './GeneralRemoteServerUpdates' - -const storeMock = vi.hoisted(() => ({ - state: { - settingsSearchQuery: '', - remoteServerUpdates: new Map([ - [ - 'server-a', - { - environmentId: 'server-a', - name: 'Test server A', - phase: 'current' - } - ] - ]), - remoteServerUpdatesChecking: false, - remoteServerUpdatesRunning: false, - refreshRemoteServerUpdates: vi.fn(), - setRemoteServerUpdateDialogOpen: vi.fn() - } -})) - -vi.mock('@/store', () => ({ - useAppStore: (selector: (state: typeof storeMock.state) => unknown) => selector(storeMock.state) -})) - -describe('GeneralRemoteServerUpdates', () => { - beforeEach(() => { - storeMock.state.refreshRemoteServerUpdates.mockReset() - storeMock.state.setRemoteServerUpdateDialogOpen.mockReset() - }) - - it('matches the local update check action and forwards modifier options', async () => { - const container = document.createElement('div') - const root = createRoot(container) - await act(async () => root.render()) - storeMock.state.refreshRemoteServerUpdates.mockClear() - - const button = container.querySelector('button') - expect(button?.textContent).toContain('Check for Server Updates') - expect(button?.querySelector('svg.lucide-refresh-cw')).not.toBeNull() - expect(button?.querySelector('svg.lucide-download')).toBeNull() - expect(container.textContent).toContain('1 paired server · 1 up to date') - - await act(async () => { - button?.dispatchEvent(new MouseEvent('click', { bubbles: true, shiftKey: true })) - }) - - expect(storeMock.state.setRemoteServerUpdateDialogOpen).toHaveBeenCalledWith(true) - expect(storeMock.state.refreshRemoteServerUpdates).toHaveBeenCalledWith({ - includePrerelease: true, - includePerfPrerelease: false - }) - await act(async () => root.unmount()) - }) -}) diff --git a/src/renderer/src/components/settings/VoiceDictationSettingsSection.test.tsx b/src/renderer/src/components/settings/VoiceDictationSettingsSection.test.tsx deleted file mode 100644 index d3a8c3f7175..00000000000 --- a/src/renderer/src/components/settings/VoiceDictationSettingsSection.test.tsx +++ /dev/null @@ -1,56 +0,0 @@ -// @vitest-environment happy-dom - -import { act } from 'react' -import { createRoot } from 'react-dom/client' -import { afterEach, describe, expect, it, vi } from 'vitest' -import { getDefaultVoiceSettings } from '../../../../shared/constants' -import { i18n } from '@/i18n/i18n' -import { VoiceDictationSettingsSection } from './VoiceDictationSettingsSection' - -const { shortcutLabel } = vi.hoisted(() => ({ shortcutLabel: vi.fn() })) -vi.mock('@/hooks/useShortcutLabel', () => ({ useShortcutLabel: shortcutLabel })) -vi.mock('./VoiceMicrophoneSetting', () => ({ VoiceMicrophoneSetting: () => null })) - -afterEach(async () => { - await i18n.changeLanguage('en') -}) - -describe('dictation shortcut explanations', () => { - it.each([ - ['en', '⌘E'], - ['en', 'Ctrl+E'], - ['ko', '⌘E'], - ['ko', 'Ctrl+E'] - ])('renders complete %s sentences with the platform shortcut %s', async (language, shortcut) => { - await i18n.changeLanguage(language) - shortcutLabel.mockReturnValue(shortcut) - const container = document.createElement('div') - const root = createRoot(container) - await act(async () => { - root.render( - - ) - }) - try { - const descriptions = Array.from(container.querySelectorAll('p'), (p) => p.textContent) - if (language === 'ko') { - expect(descriptions).toEqual([ - `${shortcut} 단축키를 눌러 포커스된 패널에 텍스트를 받아쓰세요.`, - `토글: ${shortcut} 단축키를 한 번 누르면 받아쓰기를 시작하고, 다시 누르면 중지합니다. 길게 누르기: ${shortcut} 단축키를 누르고 있는 동안 받아쓰기합니다.` - ]) - } else { - expect(descriptions).toEqual([ - `Press ${shortcut} to dictate text into any focused pane.`, - `Toggle: press ${shortcut} once to start, again to stop. Hold: dictate while ${shortcut} is held.` - ]) - } - } finally { - await act(async () => root.unmount()) - } - }) -}) diff --git a/src/renderer/src/components/settings/repository/execution/repository-description-templates.test.tsx b/src/renderer/src/components/settings/repository/execution/repository-description-templates.test.tsx deleted file mode 100644 index 227627884cc..00000000000 --- a/src/renderer/src/components/settings/repository/execution/repository-description-templates.test.tsx +++ /dev/null @@ -1,70 +0,0 @@ -// @vitest-environment happy-dom - -import { cleanup, render } from '@testing-library/react' -import { afterEach, describe, expect, it } from 'vitest' -import { setRendererUiLanguage } from '@/i18n/i18n' -import { RepositoryIssueCommandSetting } from './RepositoryIssueCommandSetting' -import { RepositoryHookCommandSourceSetting } from './RepositoryHookPolicySettings' - -function renderSettings(hasSharedIssueCommand: boolean): ReturnType { - return render( - <> - {}} - hasSharedIssueCommand={hasSharedIssueCommand} - issueCommandSaveError={null} - commitIssueCommand={async () => {}} - /> - {}} - onCopyTemplate={() => {}} - onAdvancedOpenChange={() => {}} - /> - - ) -} - -afterEach(async () => { - cleanup() - await setRendererUiLanguage('en') -}) - -describe('Repository settings complete translation templates', () => { - for (const language of ['en', 'ko'] as const) { - it.each([false, true])( - `preserves tokens and conditional defaults in ${language} (shared=%s)`, - async (shared) => { - await setRendererUiLanguage(language) - const view = renderSettings(shared) - const paragraphs = Array.from(view.container.querySelectorAll('p')) - const issue = paragraphs.find( - (p) => p.querySelector('code')?.textContent === '{{artifact_url}}' - ) - expect(issue?.textContent).toContain('{{artifact_url}}') - expect(issue?.textContent).not.toContain('') - const defaultHelp = paragraphs.find( - (p) => p.querySelector('code')?.textContent === 'orca.yaml' - ) - if (language === 'ko') { - expect(issue?.textContent).toContain('변수를 사용하세요.') - expect(defaultHelp?.textContent?.includes('있는 경우')).toBe(!shared) - } else { - expect(defaultHelp?.textContent?.includes('when one exists')).toBe(!shared) - } - const sourceHelp = paragraphs.find((p) => - p.textContent?.includes( - language === 'ko' ? '로컬 명령이 모두' : 'and local commands exist' - ) - ) - expect(sourceHelp?.querySelector('code')?.textContent).toBe('orca.yaml') - } - ) - } -}) diff --git a/src/renderer/src/components/sidebar/use-worktree-activity-statuses.test.ts b/src/renderer/src/components/sidebar/use-worktree-activity-statuses.test.ts deleted file mode 100644 index c53558f3962..00000000000 --- a/src/renderer/src/components/sidebar/use-worktree-activity-statuses.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { describe, expect, it, afterEach, vi } from 'vitest' -import { shallow } from 'zustand/shallow' -import { selectWorktreeActivityStatuses } from './use-worktree-activity-statuses' - -type StatusState = Parameters[0] - -function makeStatusState(): StatusState { - return { - tabsByWorktree: {}, - browserTabsByWorktree: {}, - unifiedTabsByWorktree: {}, - structuredChatSleptAtByPaneKey: {}, - runtimePaneTitlesByTabId: {}, - ptyIdsByTabId: {}, - terminalLayoutsByTabId: {}, - agentStatusEpoch: 0, - agentStatusByPaneKey: {}, - migrationUnsupportedByPtyId: {}, - retainedAgentsByPaneKey: {}, - runtimeAgentOrchestrationByPaneKey: {} - } -} - -describe('selectWorktreeActivityStatuses', () => { - it('stays shallow-equal when an unrelated worktree receives activity updates', () => { - const state = makeStatusState() - const unrelatedUpdate: StatusState = { - ...state, - agentStatusEpoch: 1, - browserTabsByWorktree: { - other: [] - }, - runtimePaneTitlesByTabId: { - 'other-tab': { 0: 'codex [working]' } - }, - ptyIdsByTabId: { - 'other-tab': ['other-pty'] - } - } - - expect( - shallow( - selectWorktreeActivityStatuses(state, ['visible']), - selectWorktreeActivityStatuses(unrelatedUpdate, ['visible']) - ) - ).toBe(true) - }) -}) - -const { rejectAppStoreAccess } = vi.hoisted(() => ({ - rejectAppStoreAccess: vi.fn(() => { - throw new Error('Pure helper tests must not access the app store') - }) -})) - -vi.mock('@/store', () => ({ - useAppStore: Object.assign(rejectAppStoreAccess, { - getState: rejectAppStoreAccess, - getInitialState: rejectAppStoreAccess, - setState: rejectAppStoreAccess, - subscribe: rejectAppStoreAccess - }) -})) - -afterEach(() => { - expect(rejectAppStoreAccess).not.toHaveBeenCalled() -}) diff --git a/src/renderer/src/components/status-bar/workspace-space-treemap.test.tsx b/src/renderer/src/components/status-bar/workspace-space-treemap.test.tsx deleted file mode 100644 index 5193b30d605..00000000000 --- a/src/renderer/src/components/status-bar/workspace-space-treemap.test.tsx +++ /dev/null @@ -1,65 +0,0 @@ -// @vitest-environment happy-dom - -import { cleanup, fireEvent, render, screen } from '@testing-library/react' -import { useState } from 'react' -import { afterEach, describe, expect, it } from 'vitest' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-space-types' -import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' -import { WorkspaceSpaceTreemap } from './workspace-space-treemap' - -const worktree: WorkspaceSpaceWorktree = { - worktreeId: 'repo::/workspace', - repoId: 'repo', - executionHostId: 'local', - repoDisplayName: 'repo', - repoPath: '/repo', - displayName: 'workspace', - path: '/workspace', - branch: 'main', - isMainWorktree: false, - isRemote: false, - isSparse: false, - canDelete: true, - lastActivityAt: 0, - status: 'ok', - error: null, - scannedAt: 0, - sizeBytes: 4096, - reclaimableBytes: 4096, - skippedEntryCount: 0, - topLevelItems: [ - { name: 'node_modules', path: '/workspace/node_modules', kind: 'directory', sizeBytes: 3072 } - ], - omittedTopLevelItemCount: 0, - omittedTopLevelSizeBytes: 0 -} - -function TreemapHarness(): React.JSX.Element { - const [selectedWorktreeId, setSelectedWorktreeId] = useState(null) - const [zoomId, setZoomId] = useState(null) - return ( - - ) -} - -afterEach(cleanup) - -describe('WorkspaceSpaceTreemap', () => { - it('opens a workspace from its tile and returns to the overview', () => { - render() - - fireEvent.click(screen.getByRole('button', { name: /workspace, 4/ })) - expect(screen.getByText('Folder sizes')).toBeTruthy() - expect(screen.getByText('node_modules')).toBeTruthy() - - fireEvent.click(screen.getByRole('button', { name: 'All' })) - expect(screen.getByText('Click a workspace to zoom')).toBeTruthy() - }) -}) diff --git a/src/renderer/src/components/terminal-pane/terminal-cursor-inactive-style.test.ts b/src/renderer/src/components/terminal-pane/terminal-cursor-inactive-style.test.ts deleted file mode 100644 index faa4e602e93..00000000000 --- a/src/renderer/src/components/terminal-pane/terminal-cursor-inactive-style.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import type { PaneManager, ManagedPane } from '@/lib/pane-manager/pane-manager' -import { getDefaultSettings } from '../../../../shared/constants' -import { applyTerminalAppearance } from './terminal-appearance' - -describe('terminal inactive cursor style', () => { - it('keeps blurred non-block cursors from rendering as an outline box', () => { - const options = { - cursorStyle: 'block' as const, - cursorInactiveStyle: 'outline' as const - } - const terminal = { - options, - cols: 80, - rows: 24 - } as unknown as ManagedPane['terminal'] - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: this fixture supplies the pane members used by appearance logic. - const pane = { id: 1, terminal } as ManagedPane - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: this fixture supplies the manager members used by appearance logic. - const manager = { - getPanes: () => [pane], - setPaneLigaturesEnabled: vi.fn(), - setPaneInlineImagesEnabled: vi.fn(), - setPaneStyleOptions: vi.fn() - } as unknown as PaneManager - const settings = { - ...getDefaultSettings('/tmp'), - terminalCursorStyle: 'bar' as const - } - - applyTerminalAppearance( - manager, - settings, - false, - new Map(), - new Map(), - 'false', - new Map(), - new Map() - ) - - expect(options.cursorStyle).toBe('bar') - expect(options.cursorInactiveStyle).toBe('bar') - }) -}) diff --git a/src/renderer/src/components/terminal-pane/use-notification-dispatch-verdict.test.ts b/src/renderer/src/components/terminal-pane/use-notification-dispatch-verdict.test.ts deleted file mode 100644 index 9d122b91762..00000000000 --- a/src/renderer/src/components/terminal-pane/use-notification-dispatch-verdict.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { dispatchTerminalNotification } from './use-notification-dispatch' -import { - PANE_KEY, - getLastNotificationDispatchArg, - makeAgentStatus, - resetNotificationDispatchMockState, - type NotificationDispatchMockState -} from './notification-dispatch-test-harness' - -vi.mock('@/store', async () => { - const harness = await import('./notification-dispatch-test-harness') - return harness.createNotificationDispatchStoreModuleMock() -}) - -vi.mock('@/lib/desktop-notification-sound', async () => { - const harness = await import('./notification-dispatch-test-harness') - return harness.createDesktopNotificationSoundModuleMock() -}) - -let mockState: NotificationDispatchMockState - -// Use the event row’s shared verdict so StopFailure says failed instead of finished. -describe('dispatchTerminalNotification verdict', () => { - beforeEach(() => { - mockState = resetNotificationDispatchMockState() - }) - - afterEach(() => { - vi.unstubAllGlobals() - }) - - it.each([ - [{ mainAgent: { state: 'done', outcome: 'failure', stateStartedAt: 1 } }, 'failure'], - [{ mainAgent: { state: 'done', outcome: 'cancellation', stateStartedAt: 1 } }, 'cancellation'], - [{ interrupted: true }, 'cancellation'], - [{}, undefined] - ] as const)('passes %j as the turn outcome %s', (overrides, outcome) => { - mockState.agentStatusByPaneKey[PANE_KEY] = makeAgentStatus(PANE_KEY, overrides) - - dispatchTerminalNotification('wt-primary', { - source: 'agent-task-complete', - terminalTitle: 'codex', - paneKey: PANE_KEY - }) - - expect(getLastNotificationDispatchArg()).toMatchObject({ - agentState: 'done', - agentTurnOutcome: outcome - }) - }) -}) diff --git a/src/renderer/src/components/workspace-emoji/WorkspaceEmojiSuggestionPopover.test.tsx b/src/renderer/src/components/workspace-emoji/WorkspaceEmojiSuggestionPopover.test.tsx deleted file mode 100644 index 524707485f6..00000000000 --- a/src/renderer/src/components/workspace-emoji/WorkspaceEmojiSuggestionPopover.test.tsx +++ /dev/null @@ -1,59 +0,0 @@ -// @vitest-environment happy-dom - -import { useRef } from 'react' -import { cleanup, render, screen } from '@testing-library/react' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { WorkspaceEmojiSuggestionPopover } from './WorkspaceEmojiSuggestionPopover' -import type { WorkspaceEmojiSuggestion } from '@/lib/workspace-emoji-shortcodes' - -Element.prototype.scrollIntoView ??= () => {} - -const SUGGESTIONS: WorkspaceEmojiSuggestion[] = [ - { shortcode: 'smile', emoji: '😄' }, - { shortcode: 'smiley', emoji: '😃' }, - { shortcode: 'smirk', emoji: '😏' } -] - -function PopoverHarness({ commandValue }: { commandValue: string }): React.JSX.Element { - const anchorRef = useRef(null) - - return ( -
- - {}} - onOpenChange={() => {}} - onSelect={() => {}} - open - suggestions={SUGGESTIONS} - /> -
- ) -} - -describe('WorkspaceEmojiSuggestionPopover', () => { - let scrollIntoView: ReturnType - - beforeEach(() => { - scrollIntoView = vi.spyOn(Element.prototype, 'scrollIntoView').mockImplementation(() => {}) - }) - - afterEach(() => { - scrollIntoView.mockRestore() - cleanup() - }) - - it('scrolls the externally selected suggestion into view', async () => { - const { rerender } = render() - await screen.findByText(':smirk:') - scrollIntoView.mockClear() - - rerender() - - const scrolled = scrollIntoView.mock.instances as unknown as Element[] - expect(scrolled.some((node) => node.getAttribute('data-value') === 'emoji:smirk')).toBe(true) - }) -}) diff --git a/src/renderer/src/i18n/catalog-nested-settings.test.ts b/src/renderer/src/i18n/catalog-nested-settings.test.ts deleted file mode 100644 index 40b1a718ffb..00000000000 --- a/src/renderer/src/i18n/catalog-nested-settings.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import i18next from 'i18next' -import { expect, it } from 'vitest' -import { parsePluginLanguagePackArtifact } from '../../../shared/plugins/plugin-language-pack-artifact' -import en from './locales/en.json' -import es from './locales/es.json' -import fr from './locales/fr.json' -import ja from './locales/ja.json' -import ko from './locales/ko.json' -import pt from './locales/pt.json' -import zh from './locales/zh.json' - -const AGENT_SETTINGS_KEYS = [ - 'environmentName', - 'environmentValue', - 'savedEnvironment', - 'newEnvironment', - 'removeEnvironment', - 'loadingHost', - 'updateHost', - 'readFailed', - 'saveFailed', - 'hostDefaults', - 'save' -] as const - -it.each([ - ['en', en], - ['es', es], - ['fr', fr], - ['ja', ja], - ['ko', ko], - ['pt', pt], - ['zh', zh] -] as const)( - 'keeps %s agent settings usable as nested language-pack translations', - async (locale, catalog) => { - // Bundled security copy is intentionally unavailable to plugin language packs. - expect( - parsePluginLanguagePackArtifact(JSON.stringify({ settings: catalog.settings })) - ).toMatchObject({ ok: true }) - - const instance = i18next.createInstance() - await instance.init({ - lng: locale, - fallbackLng: false, - resources: { [locale]: { translation: catalog } }, - ignoreJSONStructure: false - }) - for (const key of AGENT_SETTINGS_KEYS) { - expect(instance.t(`settings.agents.${key}`, { name: 'PATH' })).toBe( - catalog.settings.agents[key].replace('{{name}}', 'PATH') - ) - } - expect(instance.t('settings.appearance.chat.title')).toBe( - catalog.settings.appearance.chat.title - ) - } -) diff --git a/src/shared/codex-permission-policy.test.ts b/src/shared/codex-permission-policy.test.ts deleted file mode 100644 index 63003a7279e..00000000000 --- a/src/shared/codex-permission-policy.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { codexStructuredPermissionPolicy } from './codex-permission-policy' - -const FULL_ACCESS = { - approvalPolicy: 'never', - sandbox: 'danger-full-access', - approvalsReviewer: 'user' -} -const ASK = { approvalPolicy: 'on-request', sandbox: 'read-only', approvalsReviewer: 'user' } - -describe('codexStructuredPermissionPolicy', () => { - it('maps Full access to no prompts and no sandbox', () => { - expect(codexStructuredPermissionPolicy('full-access')).toEqual(FULL_ACCESS) - }) - - it('states every Ask field, the human reviewer too', () => { - expect(codexStructuredPermissionPolicy('ask')).toEqual(ASK) - }) - - it('keeps Approve for me in the configured workspace sandbox', () => { - expect(codexStructuredPermissionPolicy('auto')).toEqual({ - approvalPolicy: 'on-request', - sandbox: 'workspace-write', - approvalsReviewer: 'auto_review' - }) - }) - - it('names a sandbox mode for every mode', () => { - for (const mode of ['ask', 'auto', 'full-access'] as const) { - expect(codexStructuredPermissionPolicy(mode)).not.toHaveProperty('sandboxPolicy') - expect(typeof codexStructuredPermissionPolicy(mode).sandbox).toBe('string') - } - }) - - it('asks for a mode Codex does not have', () => { - expect(codexStructuredPermissionPolicy('accept-edits')).toEqual(ASK) - }) -}) diff --git a/src/shared/secure-file.test.ts b/src/shared/secure-file.test.ts index 0cb16407cdd..9b83d9fc288 100644 --- a/src/shared/secure-file.test.ts +++ b/src/shared/secure-file.test.ts @@ -4,17 +4,14 @@ import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { - __getSecureFileHardeningCacheStateForTests, __resetSecureFileHardenedPathsForTests, hardenExistingSecureFile, - isUnreadableError, writeSecureFile } from './secure-file' import { setWindowsSecurityForTests, resetWindowsSecurityLoadForTests } from './windows-security-addon' -import { createFakeWindowsSecurity } from './windows-security-addon.test-fixture' const chmodFailure = vi.hoisted((): { code: string | null } => ({ code: null })) @@ -61,18 +58,6 @@ describe('POSIX secure files', () => { return dir } - it('never touches the Windows ACL addon off win32', () => { - Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' }) - const fake = createFakeWindowsSecurity() - setWindowsSecurityForTests(fake) - const targetPath = join(tempDir(), 'secret.json') - - writeSecureFile(targetPath, 'contents') - hardenExistingSecureFile(targetPath) - - expect(fake.calls).toEqual([]) - }) - posixModeIt('restricts the published file and its directory by mode', () => { Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' }) const userDataPath = tempDir() @@ -114,60 +99,8 @@ describe('POSIX secure files', () => { expect(() => hardenExistingSecureFile(targetPath)).toThrow('EIO') } ) - - posixModeIt('LRU-bounds POSIX hardening entries while keeping recent paths cached', () => { - Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' }) - __resetSecureFileHardenedPathsForTests({ - maxEntries: 2, - maxKeyBytes: 4096, - maxTotalKeyBytes: 8192 - }) - const userDataPath = tempDir() - const firstPath = join(userDataPath, 'first.json') - const secondPath = join(userDataPath, 'second.json') - writeFileSync(firstPath, '{}') - writeFileSync(secondPath, '{}') - - hardenExistingSecureFile(firstPath) - hardenExistingSecureFile(secondPath) - expect(__getSecureFileHardeningCacheStateForTests().paths.paths).toEqual([ - userDataPath, - secondPath - ]) - - hardenExistingSecureFile(firstPath) - expect(__getSecureFileHardeningCacheStateForTests().paths.paths).toEqual([ - userDataPath, - firstPath - ]) - }) }) function statMode(path: string): number { return statSync(path).mode & 0o777 } - -describe('isUnreadableError', () => { - const withCode = (code: string): NodeJS.ErrnoException => Object.assign(new Error(code), { code }) - - it('reports a denied read', () => { - expect(isUnreadableError(withCode('EPERM'))).toBe(true) - expect(isUnreadableError(withCode('EACCES'))).toBe(true) - }) - - /** AV locks (EBUSY) or fd exhaustion (EMFILE) reveal no contents and must never authorize regenerate-and-overwrite. */ - it('reports a read that never reached the contents for any other reason', () => { - expect(isUnreadableError(withCode('EBUSY'))).toBe(true) - expect(isUnreadableError(withCode('EMFILE'))).toBe(true) - expect(isUnreadableError(withCode('ENFILE'))).toBe(true) - expect(isUnreadableError(withCode('EIO'))).toBe(true) - }) - - /** Missing files permit creation; parsed garbage permits repair. Neither is an unreadable-content failure. */ - it('does not report a missing file or a parse failure', () => { - expect(isUnreadableError(withCode('ENOENT'))).toBe(false) - expect(isUnreadableError(new SyntaxError('Unexpected end of JSON input'))).toBe(false) - expect(isUnreadableError(withCode('EISDIR'))).toBe(false) - expect(isUnreadableError(undefined)).toBe(false) - }) -}) diff --git a/src/shared/setup-agent-sequencing.windows.test.ts b/src/shared/setup-agent-sequencing.windows.test.ts index b27ee5ccc41..4963a2c8912 100644 --- a/src/shared/setup-agent-sequencing.windows.test.ts +++ b/src/shared/setup-agent-sequencing.windows.test.ts @@ -5,10 +5,7 @@ import { tmpdir } from 'node:os' import { afterEach, describe, expect, it } from 'vitest' -import { - createSequencedSetupAgentCommands, - SETUP_AGENT_SEQUENCE_STARTUP_COMMAND_ENV -} from './setup-agent-sequencing' +import { createSequencedSetupAgentCommands } from './setup-agent-sequencing' import { quotePowerShellLiteral } from './powershell-native-argument' const TEMP_DIRS: string[] = [] @@ -86,20 +83,6 @@ describe.skipIf(process.platform !== 'win32')('Windows setup-agent sequencing', WINDOWS_PROCESS_TEST_TIMEOUT_MS ) - it('keeps the startup command out of generated cmd.exe source', () => { - const startupCommand = 'agent --prompt "& | ^ % ! 한글 trailing\\"' - const commands = createSequencedSetupAgentCommands({ - runnerScriptPath: 'C:\\repo\\setup-runner.cmd', - startupCommand, - platform: 'windows', - nonce: 'windows-sequence' - }) - - expect(commands.setupCommand).not.toContain(startupCommand) - expect(commands.startupCommand).not.toContain(startupCommand) - expect(commands.startupEnv?.[SETUP_AGENT_SEQUENCE_STARTUP_COMMAND_ENV]).toBe(startupCommand) - }) - it( 'propagates setup failure without launching the agent', async () => { diff --git a/src/shared/sidebar-feed-client/sidebar-feed-snapshot.test.ts b/src/shared/sidebar-feed-client/sidebar-feed-snapshot.test.ts index ee4f0d614c0..96ee6f18563 100644 --- a/src/shared/sidebar-feed-client/sidebar-feed-snapshot.test.ts +++ b/src/shared/sidebar-feed-client/sidebar-feed-snapshot.test.ts @@ -6,7 +6,7 @@ import { indexSidebarFeed } from '../sidebar-list/sidebar-feed-index' import { composeWorktreeHostIdentity } from '../worktree/host-qualified-identity' import { WorkspaceRowsSnapshotSchema, type WorkspaceRow } from '../sidebar-list/workspace-rows' import { SidebarFeedReader, type SidebarFeedReaderRead } from './sidebar-feed-reader' -import { installSidebarFeedSnapshot, type SidebarFeedSnapshot } from './sidebar-feed-snapshot' +import type { SidebarFeedSnapshot } from './sidebar-feed-snapshot' const WORKSPACES = 1000 @@ -115,10 +115,4 @@ describe('sidebar feed snapshot', () => { // A domain the change did not touch keeps its map. expect(after.domains.review).toBe(before.domains.review) }) - - it('keeps the snapshot itself when the install is the same', async () => { - const host = await readHost() - const snapshot = host.snapshot() - expect(installSidebarFeedSnapshot(snapshot.installed, snapshot)).toBe(snapshot) - }) }) diff --git a/src/shared/source-control-launch-agent-selection.spec.ts b/src/shared/source-control-launch-agent-selection.spec.ts deleted file mode 100644 index 1862122d871..00000000000 --- a/src/shared/source-control-launch-agent-selection.spec.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { getDefaultSettings } from './constants' -import type { GlobalSettings } from './global-settings-types' -import type { Repo } from './repo-types' -import type { TuiAgent } from './tui-agent' -import { - resolveSourceControlLaunchAgentScope, - summarizeReposOverridingActionRecipe -} from './source-control-launch-agent-selection' - -function settingsWithGlobalResolveAgent(agentId: TuiAgent): GlobalSettings { - const base = getDefaultSettings('/tmp') - return { - ...base, - defaultTuiAgent: agentId, - sourceControlAi: { - ...base.sourceControlAi!, - enabled: true, - actions: { - ...base.sourceControlAi!.actions, - resolveConflicts: { agentId, commandInputTemplate: '{basePrompt}', agentArgs: '' } - } - } - } -} - -function repoWithResolveAgent(agentId: TuiAgent): Pick { - return { - sourceControlAi: { - actionOverrides: { - resolveConflicts: { agentId, commandInputTemplate: '{basePrompt}', agentArgs: '' } - } - } - } -} - -describe('resolveSourceControlLaunchAgentScope', () => { - it('flags a repo override that pins a different agent than the global default', () => { - const scope = resolveSourceControlLaunchAgentScope({ - settings: settingsWithGlobalResolveAgent('claude'), - repo: repoWithResolveAgent('codex'), - actionId: 'resolveConflicts' - }) - expect(scope).toEqual({ - effectiveAgentId: 'codex', - globalAgentId: 'claude', - overridesGlobalAgent: true - }) - }) - - it('does not flag a repo override that matches the global agent', () => { - const scope = resolveSourceControlLaunchAgentScope({ - settings: settingsWithGlobalResolveAgent('claude'), - repo: repoWithResolveAgent('claude'), - actionId: 'resolveConflicts' - }) - expect(scope.overridesGlobalAgent).toBe(false) - }) - - it('does not flag when there is no repo override', () => { - const scope = resolveSourceControlLaunchAgentScope({ - settings: settingsWithGlobalResolveAgent('claude'), - repo: null, - actionId: 'resolveConflicts' - }) - expect(scope).toEqual({ - effectiveAgentId: 'claude', - globalAgentId: 'claude', - overridesGlobalAgent: false - }) - }) - - it('falls back to the default agent when no global recipe agent is set', () => { - const base = getDefaultSettings('/tmp') - const settings: GlobalSettings = { - ...base, - defaultTuiAgent: 'claude', - sourceControlAi: { ...base.sourceControlAi!, enabled: true } - } - const scope = resolveSourceControlLaunchAgentScope({ - settings, - repo: repoWithResolveAgent('codex'), - actionId: 'resolveConflicts' - }) - expect(scope.globalAgentId).toBe('claude') - expect(scope.overridesGlobalAgent).toBe(true) - }) -}) - -function repoOverriding( - id: string, - displayName: string, - agentId: TuiAgent -): Pick { - return { id, displayName, ...repoWithResolveAgent(agentId) } -} - -describe('summarizeReposOverridingActionRecipe', () => { - it('lists repos with any action recipe override', () => { - const summary = summarizeReposOverridingActionRecipe({ - repos: [ - repoOverriding('repo-1', 'App', 'claude'), - { - id: 'repo-2', - displayName: 'Web', - sourceControlAi: { - actionOverrides: { - resolveConflicts: { - commandInputTemplate: '{basePrompt}\n\nUse project conflict rules.', - agentArgs: '--model gpt-5.4-mini' - } - } - } - }, - { id: 'repo-3', displayName: 'Docs' } - ], - actionId: 'resolveConflicts' - }) - - expect(summary).toEqual({ - count: 2, - overrides: [ - { repoId: 'repo-1', repoName: 'App', fields: ['agent', 'commandTemplate', 'agentArgs'] }, - { repoId: 'repo-2', repoName: 'Web', fields: ['commandTemplate', 'agentArgs'] } - ] - }) - }) - - it('includes legacy repo instructions as command template overrides', () => { - const summary = summarizeReposOverridingActionRecipe({ - repos: [ - { - id: 'repo-1', - displayName: 'App', - sourceControlAi: { - instructionsByOperation: { - commitMessage: 'Use project style.' - } - } - } - ], - actionId: 'commitMessage' - }) - - expect(summary).toEqual({ - count: 1, - overrides: [{ repoId: 'repo-1', repoName: 'App', fields: ['commandTemplate'] }] - }) - }) -}) diff --git a/src/shared/source-control-plan-contracts.test.ts b/src/shared/source-control-plan-contracts.test.ts index 192eea7fc4e..d69656416de 100644 --- a/src/shared/source-control-plan-contracts.test.ts +++ b/src/shared/source-control-plan-contracts.test.ts @@ -1,4 +1,3 @@ -import './source-control-launch-agent-selection.spec' import './omp-source-control-discovery.spec' import './source-control-ai-policy-regression.spec' import './commit-message-omp.spec' diff --git a/src/shared/structured-agent-session-first-frame-picker.spec.ts b/src/shared/structured-agent-session-first-frame-picker.spec.ts index a139b7259ce..f303ca143ea 100644 --- a/src/shared/structured-agent-session-first-frame-picker.spec.ts +++ b/src/shared/structured-agent-session-first-frame-picker.spec.ts @@ -73,22 +73,6 @@ describe('the first frame of every agent’s picker', () => { } ) - it.each(AGENTS)( - '%s: a warm host catalog lists its models before the session reports', - (agent) => { - const { state, snapshot } = firstFrame(agent, { - ...HOST_CATALOG, - listingNamesConfiguredModel: false - }) - expect(state.catalogSource).toBe('host') - const model = snapshot.find((descriptor) => descriptor.id === 'model') - expect( - model?.kind.type === 'select' && model.kind.choices.map((choice) => choice.value) - ).toEqual(['model-listed']) - expect(state.record.values.model).toBeUndefined() - } - ) - it.each(AGENTS)( '%s: a new chat names the listed model and its effort when the host says it runs them', (agent) => { diff --git a/src/shared/terminal-partial-escape-tail.fuzz.test.ts b/src/shared/terminal-partial-escape-tail.fuzz.test.ts index d22cc4a2df7..6c2b7c67712 100644 --- a/src/shared/terminal-partial-escape-tail.fuzz.test.ts +++ b/src/shared/terminal-partial-escape-tail.fuzz.test.ts @@ -13,50 +13,6 @@ const oracle = (pending: string, chunk: string): string => { return tail.length > MAX_PARTIAL_ESCAPE_TAIL_LENGTH ? '' : tail } -// Every byte class the scanner branches on, plus code units the gate's `includes` must not confuse. -const ALPHABET = [ - '\x1b', - '\x18', - '\x1a', - '\x07', - '\x00', - '\\', - '[', - ']', - 'P', - 'X', - '^', - '_', - '(', - ' ', - '0', - ';', - 'm', - '\n', - '\x7f', - '\x9c', - 'é', - '中', - '\u{1f600}', - '\ud83d', - '\udc00' -] - -// One representative of every state the scanner can be left in. -const PENDINGS = [ - '', - '\x1b', - '\x1b[', - '\x1b[3', - '\x1b]0;ti', - '\x1b]0;ti\x1b', - '\x1bP dcs', - '\x1bPx\x1b', - '\x1b(', - '\x1b ', - '\x1b[1;2;3' -] - const SEQUENCES = [ '\x1b[1;31m', '\x1b]0;my title\x07', @@ -79,27 +35,7 @@ const SEQUENCES = [ '\x1bX sos \x1b\x1bP' ] -// Count corpus depth separately: astral symbols occupy two UTF-16 units, so text.length would drop valid depth-N strings. -function* stringsUpTo(maxDepth: number): Generator<{ depth: number; text: string }> { - yield { depth: 0, text: '' } - for (let depth = 1; depth <= maxDepth; depth++) { - const digits = Array.from({ length: depth }, () => 0) - for (;;) { - yield { depth, text: digits.map((digit) => ALPHABET[digit]).join('') } - let place = depth - 1 - while (place >= 0 && ++digits[place] === ALPHABET.length) { - digits[place--] = 0 - } - if (place < 0) { - break - } - } - } -} - describe('advancePartialEscapeTail differential fuzz', () => { - let checked = 0 - let foldSplits = 0 // Re-split the whole stream to exercise oscEsc/stringEsc boundaries; pre-normalized tails make the fold assertion tautological. const checkFolds = (text: string): void => { if (text.length > 32) { @@ -107,7 +43,6 @@ describe('advancePartialEscapeTail differential fuzz', () => { } const whole = extractPartialEscapeTail(text) for (let cut = 0; cut <= text.length; cut++) { - foldSplits++ const folded = extractPartialEscapeTail( extractPartialEscapeTail(text.slice(0, cut)) + text.slice(cut) ) @@ -117,7 +52,6 @@ describe('advancePartialEscapeTail differential fuzz', () => { } } const check = (pending: string, chunk: string): void => { - checked++ const actual = advancePartialEscapeTail(pending, chunk) if (actual !== oracle(pending, chunk)) { expect.fail(`gate diverged: ${JSON.stringify({ pending, chunk, actual })}`) @@ -132,20 +66,6 @@ describe('advancePartialEscapeTail differential fuzz', () => { checkFolds(pending + chunk) } - it('matches the unguarded oracle on every chunk up to length 4', () => { - for (const { text: chunk } of stringsUpTo(3)) { - for (const pending of PENDINGS) { - check(pending, chunk) - } - } - for (const { depth, text: chunk } of stringsUpTo(4)) { - if (depth === 4) { - check('', chunk) - check('\x1b[', chunk) - } - } - }) - it('matches at every split point of known sequences', () => { for (const sequence of SEQUENCES) { for (let cut = 0; cut <= sequence.length; cut++) { @@ -161,22 +81,4 @@ describe('advancePartialEscapeTail differential fuzz', () => { } } }) - - it('matches across the tail-length cap', () => { - const max = MAX_PARTIAL_ESCAPE_TAIL_LENGTH - for (const length of [max - 1, max, max + 1, max + 100]) { - const osc = `\x1b]0;${'x'.repeat(length - 4)}` - for (const chunk of ['', 'y', '\x07', '\x1b\\', '\x1b', 'plain\n', 'x'.repeat(5000)]) { - check(osc, chunk) - check('', osc + chunk) - check('\x1b]0;', osc.slice(4) + chunk) - } - } - }) - - it('ran the whole corpus', () => { - expect(checked).toBe(963_819) - // Completed strings retain only ESC, so the same corpus has fewer tail splits. - expect(foldSplits).toBe(6_234_666) - }) }) diff --git a/src/shared/terminal-restore-parity-writes.test.ts b/src/shared/terminal-restore-parity-writes.test.ts index 342e7effd54..2f91679d4c3 100644 --- a/src/shared/terminal-restore-parity-writes.test.ts +++ b/src/shared/terminal-restore-parity-writes.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest' +import { describe, expect, it } from 'vitest' import { createRendererParityTerminal, cursorPosition, @@ -18,43 +18,6 @@ type AsyncOscParser = { } describe('terminal parity fixture writes', () => { - it('queues every original chunk and resolves only after the last callback', async () => { - const { terminal } = createRendererParityTerminal({ cols: 8, rows: 2 }) - const writes: { data: string | Uint8Array; callback?: () => void }[] = [] - try { - vi.spyOn(terminal, 'write').mockImplementation((data, callback) => { - writes.push({ data, callback }) - }) - const chunks = ['A\x1b[', '', '31mB', '\x1b[0mC'] - let completed = false - const pending = writeChunksToTerminal(terminal, chunks).then(() => { - completed = true - }) - expect(writes.map(({ data }) => data)).toEqual(chunks) - expect(writes.slice(0, -1).every(({ callback }) => callback === undefined)).toBe(true) - await Promise.resolve() - expect(completed).toBe(false) - writes.at(-1)?.callback?.() - await pending - expect(completed).toBe(true) - } finally { - terminal.dispose() - vi.restoreAllMocks() - } - }) - - it('completes an empty batch without writing or scheduling work', async () => { - const { terminal } = createRendererParityTerminal({ cols: 8, rows: 2 }) - try { - const write = vi.spyOn(terminal, 'write') - await writeChunksToTerminal(terminal, []) - expect(write).not.toHaveBeenCalled() - } finally { - terminal.dispose() - vi.restoreAllMocks() - } - }) - it('waits for an asynchronous parser barrier before exposing later chunks', async () => { const { terminal } = createRendererParityTerminal({ cols: 8, rows: 2 }) let signalEntered = (): void => {} diff --git a/src/shared/terminal-title-classification-corpus.test.ts b/src/shared/terminal-title-classification-corpus.test.ts index 7eaa3cf3261..5a5c11fa233 100644 --- a/src/shared/terminal-title-classification-corpus.test.ts +++ b/src/shared/terminal-title-classification-corpus.test.ts @@ -2,7 +2,6 @@ import { describe, expect, it } from 'vitest' import { isGeminiTerminalTitle } from './agent-title-core' import { getAgentLabel, isClaudeAgent } from './agent-title-identity' import { detectAgentStatusFromTitle } from './agent-title-status' -import { TERMINAL_TITLE_CLASSIFICATION_CORPUS } from './terminal-title-classification-corpus' import { getAgentLabel as getExplicitAgentLabel, isClaudeAgent as isExplicitClaudeAgent, @@ -244,12 +243,6 @@ const PINNED_CLASSIFICATIONS: readonly PinnedRow[] = [ ] describe('terminal title classification', () => { - it('covers every corpus title exactly once', () => { - expect(PINNED_CLASSIFICATIONS.map(([title]) => title)).toEqual([ - ...TERMINAL_TITLE_CLASSIFICATION_CORPUS - ]) - }) - it.each(PINNED_CLASSIFICATIONS)( 'classifies %j identically', ( diff --git a/src/shared/worker-terminal-host-scope.test.ts b/src/shared/worker-terminal-host-scope.test.ts index a9f24125f37..ac48c506184 100644 --- a/src/shared/worker-terminal-host-scope.test.ts +++ b/src/shared/worker-terminal-host-scope.test.ts @@ -5,10 +5,7 @@ import { projectOrchestrationFleet, type FleetDurableWorker } from './orchestration-fleet-projection' -import { - parseWorkerTerminalHostScope, - readWorkerTerminalHostScope -} from './worker-terminal-host-scope' +import { readWorkerTerminalHostScope } from './worker-terminal-host-scope' /** One host_scope read must drive host labels and connection fences; divergent WSL-local parsing previously made live local workers unverifiable. */ const PANE_KEY = 'tab-host:leaf-host' @@ -174,23 +171,4 @@ describe('worker terminal host scope', () => { } }) } - - it('keeps the strict scope contract the process-liveness path depends on', () => { - expect(parseWorkerTerminalHostScope('{"kind":"ssh","targetId":"host-1"}')).toEqual({ - kind: 'ssh', - targetId: 'host-1' - }) - expect( - parseWorkerTerminalHostScope('{"kind":"wsl","hostId":"local","distro":"Ubuntu"}') - ).toEqual({ kind: 'wsl', hostId: 'local', distro: 'Ubuntu' }) - expect(parseWorkerTerminalHostScope('{"kind":"local","hostId":"local"}')).toEqual({ - kind: 'local', - hostId: 'local' - }) - // A scope missing the facts its kind requires is not a scope. - expect(parseWorkerTerminalHostScope('{"kind":"wsl","hostId":"local"}')).toBeNull() - expect(parseWorkerTerminalHostScope('{"kind":"ssh"}')).toBeNull() - expect(parseWorkerTerminalHostScope('local:workspace-1')).toBeNull() - expect(parseWorkerTerminalHostScope(null)).toBeNull() - }) }) diff --git a/src/shared/workspace-layout/workspace-layout-fact-locations.test.ts b/src/shared/workspace-layout/workspace-layout-fact-locations.test.ts index 5d899865044..fe7a2e1d867 100644 --- a/src/shared/workspace-layout/workspace-layout-fact-locations.test.ts +++ b/src/shared/workspace-layout/workspace-layout-fact-locations.test.ts @@ -5,8 +5,7 @@ import { LOCAL_EXECUTION_HOST_ID } from '../execution-host' import { DISK_TABLES, type DiskFieldWritten, - type LayoutSource, - type UnwrittenLayoutSource + type LayoutSource } from './workspace-layout-disk-fields' import { EDITOR_FILE_KEY_FIELDS } from './workspace-layout-editor-tab-file' import { loadWorkspaceLayout } from './workspace-layout-load' @@ -18,37 +17,6 @@ import { saveWorkspaceLayout } from './workspace-layout-save' import { addWorkspace, GIT_KEY, leaf } from './workspace-layout-session.test-fixture' import type { WorkspaceSessionState } from '../workspace-session-state-types' -// A model or side-data field no disk field is written from fails here. -const everySourceIsWritten: [UnwrittenLayoutSource] extends [never] ? true : UnwrittenLayoutSource = - true - -/** On-disk fields that hold one fact; each group must be written from the same source. */ -const COPIES = [ - ['row.ptyId', 'layout.ptyIdsByLeafId'], - ['row.id', 'terminalEntry.entityId'], - ['row.title', 'terminalEntry.label'], - ['row.customTitle', 'terminalEntry.customLabel'], - ['row.generatedTitle', 'terminalEntry.generatedLabel'], - ...['createdAt', 'color', 'aiVaultTitle', 'quickCommandLabel', 'isPinned', 'viewMode'].map( - (field) => [`row.${field}`, `terminalEntry.${field}`] - ), - ['row.sortOrder', 'terminalEntry.sortOrder', 'entry.sortOrder', 'group.tabOrder'], - [ - 'row.worktreeId', - 'terminalEntry.worktreeId', - 'entry.worktreeId', - 'group.worktreeId', - 'file.worktreeId', - 'browser.worktreeId', - 'sleeping.worktreeId', - 'closedTab.worktreeId' - ], - ['sleeping.paneKey', 'sleeping.tabId'], - ['terminalEntry.executionHostId', 'entry.executionHostId'], - ['entry.isPreview', 'file.isPreview'], - ['terminalEntry.groupId', 'entry.groupId', 'group.id'] -] - /** Do not mutate identity fields: broken references would test integrity rather than fact ownership. */ const IDENTITY_SOURCES = new Set([ 'tab.id', @@ -290,32 +258,6 @@ function diskValues(session: WorkspaceSessionState): Map { const ALL_SOURCES = [...new Set([...WRITTEN_BY_FIELD.values(), TAB_LIST_ORDER].flatMap(sourcesOf))] describe('each on-disk field has one source', () => { - it('is typed over every disk, model and side-data field', () => { - expect(everySourceIsWritten).toBe(true) - }) - - it('writes every copy of one fact from the same source', () => { - for (const group of COPIES) { - const sources = group.map((field) => { - const written = writtenOf(field) - return typeof written === 'string' ? written : written.from - }) - expect(new Set(sources).size, group.join(' = ')).toBe(1) - } - }) - - it('has every source populated, so a mutation can show what it writes', () => { - const loaded = richLoaded() - const empty = ALL_SOURCES.filter((source) => { - const [prefix, field] = splitSource(source) - return ( - !IDENTITY_SOURCES.has(source) && - !holdersOf(loaded, prefix).some((holder) => holder[field] != null) - ) - }) - expect(empty).toEqual([]) - }) - it('holds each placed pane record in exactly one of its two holders', () => { const loaded = richLoaded() const leaves = Object.values(loaded.layout.workspaces).flatMap((workspace) => diff --git a/src/shared/workspace-layout/workspace-layout-load-browser-repair.test.ts b/src/shared/workspace-layout/workspace-layout-load-browser-repair.test.ts index 6cb4b476d90..4c5a285feb3 100644 --- a/src/shared/workspace-layout/workspace-layout-load-browser-repair.test.ts +++ b/src/shared/workspace-layout/workspace-layout-load-browser-repair.test.ts @@ -85,15 +85,6 @@ describe("main's load of a browser record with no tab", () => { expect(resolveSessionTabRow(workspace, 'browser-1')?.tab.id).toBe(tab.id) }) - it('saves the tab, so the next load mints nothing new', () => { - const saved = saveWorkspaceLayout(load(savedSession())) - - expect( - saved.unifiedTabs?.[KEY]?.find((entry) => entry.contentType === 'browser') - ).toMatchObject({ entityId: 'browser-1', groupId: 'g2', label: 'Example' }) - expect(load(saved).changes).toEqual([]) - }) - it('mints the same id on every load, and a restart after a save keeps one tab', () => { const ids = (session: WorkspaceSessionState) => load(session) diff --git a/src/shared/workspace-session-salvage-equivalence.test.ts b/src/shared/workspace-session-salvage-equivalence.test.ts index 77ee22e88ec..d34ad0036c0 100644 --- a/src/shared/workspace-session-salvage-equivalence.test.ts +++ b/src/shared/workspace-session-salvage-equivalence.test.ts @@ -415,7 +415,6 @@ const CORPUS: [string, unknown][] = [ describe('salvage equivalence with the pre-optimization implementation', () => { let legacyParse: LegacyParse - let legacyUnionsBuilt = 0 beforeAll(async () => { // Build the legacy schema from both legacy salvage combinators and plain unions to cover both optimizations. @@ -427,7 +426,6 @@ describe('salvage equivalence with the pre-optimization implementation', () => { z: { ...actual.z, discriminatedUnion: (_key: string, options: z.ZodType[]) => { - legacyUnionsBuilt += 1 return actual.z.union(options) } } @@ -443,11 +441,6 @@ describe('salvage equivalence with the pre-optimization implementation', () => { vi.resetModules() }) - it('builds a legacy parser from the legacy combinators and plain unions', () => { - expect(legacyParse).not.toBe(parseWorkspaceSessionSalvaging) - expect(legacyUnionsBuilt).toBeGreaterThanOrEqual(2) - }) - it.each(CORPUS)('matches the legacy result for %s', (_name, payload) => { const legacy = legacyParse(payload) const current = parseWorkspaceSessionSalvaging(payload) @@ -461,14 +454,6 @@ describe('salvage equivalence with the pre-optimization implementation', () => { expect(current.droppedPaths.toSorted()).toEqual(legacy.droppedPaths.toSorted()) }) - it('rejects the same payloads the legacy parser rejects', () => { - const rejected = CORPUS.filter(([, payload]) => !legacyParse(payload).ok) - expect(rejected.length).toBeGreaterThan(0) - for (const [, payload] of rejected) { - expect(parseWorkspaceSessionSalvaging(payload).ok).toBe(false) - } - }) - it('rejects a record carrying an enumerable symbol key, as zod.record did', () => { const withSymbol: Record = { 'tab-1:leaf-1': 'inc-1' } withSymbol[Symbol('extra') as unknown as string] = 'x'