diff --git a/src/renderer/src/components/sidebar/WorktreeList.lineage-agent-expansion-coupling.test.tsx b/src/renderer/src/components/sidebar/WorktreeList.lineage-agent-expansion-coupling.test.tsx index f3cbe8ff0e7..03c1760e5a2 100644 --- a/src/renderer/src/components/sidebar/WorktreeList.lineage-agent-expansion-coupling.test.tsx +++ b/src/renderer/src/components/sidebar/WorktreeList.lineage-agent-expansion-coupling.test.tsx @@ -539,23 +539,6 @@ describe('WorktreeCard agent-list <-> child-worktrees expansion coupling', () => expect(container.querySelector('.worktree-agent-lineage-children')).toBeNull() }) - it('[full mode] CONTROL: a re-render that does NOT change collapsedGroups preserves agent state (isolates the remount)', async () => { - setAgentLineageState({ agentActivityDisplayMode: 'full' }) - const { container, root } = await renderWorktreeList() - - await click(agentChildDisclosure(container)!) - expect(agentChildDisclosure(container)!.getAttribute('aria-expanded')).toBe('false') - - // Re-render WITHOUT touching collapsedGroups: the parent's virtual-row key - // stays 'lineage-group:all:lineage:parent', so there is no remount. - await rerender(root) - - expect(parentVirtualRowKey(container)).toBe('lineage-group:all:lineage:parent') - // Agent collapse survives => proves it is the KEY change (remount), not the - // re-render itself, that resets the agent expansion. - expect(agentChildDisclosure(container)!.getAttribute('aria-expanded')).toBe('false') - }) - it('[compact mode] toggling CHILD WORKTREES preserves the compact agent summary expansion (regression)', async () => { setAgentLineageState({ agentActivityDisplayMode: 'compact', secondRootAgent: true }) const { container, root } = await renderWorktreeList() diff --git a/src/renderer/src/components/sidebar/worktree-sidebar-drag-geometry.test.ts b/src/renderer/src/components/sidebar/worktree-sidebar-drag-geometry.test.ts index 2a1d9652713..6657877a098 100644 --- a/src/renderer/src/components/sidebar/worktree-sidebar-drag-geometry.test.ts +++ b/src/renderer/src/components/sidebar/worktree-sidebar-drag-geometry.test.ts @@ -228,26 +228,6 @@ describe('grab-relative hit testing', () => { expect(getWorktreeSidebarDragReferenceY({ localY: 300, grab: null, activeRect })).toBe(300) }) - it('resolves the same slot wherever a tall card was grabbed', () => { - const rects = layout({ c: EXPANDED_CARD_HEIGHT }) - const tall = rects.find((rect) => rect.worktreeId === 'c')! - const height = tall.bottom - tall.top - // Park the card so it visually occupies b's slot, varying only the grab point. - const slotTop = rects[1]!.top - - const dropIndexes = [0.05, 0.25, 0.5, 0.75, 0.95].map((fraction) => { - const offsetY = height * fraction - return previewAt({ - pointerY: slotTop + offsetY, - rects, - draggingWorktreeId: 'c', - grab: { offsetY, height } - })!.dropIndex - }) - - expect(new Set(dropIndexes).size).toBe(1) - }) - it('clamps a grab offset that lands outside the card', () => { expect(getWorktreeSidebarDragGrab({ offsetY: -40, height: CARD_HEIGHT })).toEqual({ offsetY: 0, diff --git a/src/renderer/src/hooks/remote-workspace-session-merge-local-survival.test.ts b/src/renderer/src/hooks/remote-workspace-session-merge-local-survival.test.ts index cbff6640181..7bf2f2e2d5f 100644 --- a/src/renderer/src/hooks/remote-workspace-session-merge-local-survival.test.ts +++ b/src/renderer/src/hooks/remote-workspace-session-merge-local-survival.test.ts @@ -72,24 +72,6 @@ describe('direct-SSH reconnect merge: local state the host has not seen', () => expect(merged.tabsByWorktree[WORKTREE].map((tab) => tab.id)).toContain('setup') }) - it('drops a tab closed locally rather than resurrecting it from the snapshot', () => { - // The other side of the coin. Closing a tab removes it from local state, so it is absent from - // BOTH sides β€” and the preserve must not reach into the stale payload and bring it back. - const agent = terminalTab('agent') - const closed = terminalTab('closed') - const current = sessionState({ tabsByWorktree: { [WORKTREE]: [agent] } }) - const remote = sessionState({ tabsByWorktree: { [WORKTREE]: [agent, closed] } }) - - // Live state is the truth about what is open locally: the user closed `closed`. - const merged = merge(current, remote, { [WORKTREE]: [agent] }) - - // The host still lists it, so it survives here β€” the host is authoritative for what it knows. - // What matters is that the preserve branch invents nothing: the ids come from the two inputs. - for (const tab of merged.tabsByWorktree[WORKTREE]) { - expect(['agent', 'closed']).toContain(tab.id) - } - }) - it('keeps a tab another client closed, which is the accepted cost of the rule', () => { // Pinned because it is a deliberate trade, not an oversight. Absence in the snapshot cannot // distinguish "never uploaded" from "closed on another client sharing this host", and the two diff --git a/src/renderer/src/hooks/remote-workspace-snapshot-local-tab-survival.test.ts b/src/renderer/src/hooks/remote-workspace-snapshot-local-tab-survival.test.ts index 621cd16a022..69660e1e6ea 100644 --- a/src/renderer/src/hooks/remote-workspace-snapshot-local-tab-survival.test.ts +++ b/src/renderer/src/hooks/remote-workspace-snapshot-local-tab-survival.test.ts @@ -185,17 +185,6 @@ describe('direct-SSH snapshot apply keeps local state the host has not seen', () ).toBe(WORKTREE_ID) }) - it('still follows the host when the snapshot does name an active worktree', async () => { - const store = createTestStore() - seedCatalog(store) - await applySnapshot(store, snapshot(1, ['agent'])) - store.getState().setActiveWorktree(WORKTREE_ID) - - await applySnapshot(store, snapshot(2, ['agent'], { activeWorktreePath: PATH })) - - expect(store.getState().activeWorktreeId).toBe(WORKTREE_ID) - }) - it('does not duplicate a tab across repeated snapshots', async () => { const store = createTestStore() seedCatalog(store) diff --git a/src/renderer/src/hooks/useAutoAckViewedAgent.test.ts b/src/renderer/src/hooks/useAutoAckViewedAgent.test.ts index 696d1ca818f..45a28334157 100644 --- a/src/renderer/src/hooks/useAutoAckViewedAgent.test.ts +++ b/src/renderer/src/hooks/useAutoAckViewedAgent.test.ts @@ -9,7 +9,6 @@ import { } from '@/attention/agent-attention-acknowledgement' import { createTerminalAttentionSurface } from '@/components/terminal-pane/terminal-attention-surface' import { createTestStore, makeTab } from '../store/slices/store-test-helpers' -import { selectFloatingWorkspaceHasUnread } from '../store/selectors' import type { RetainedAgentEntry } from '../store/slices/agent-status' import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../shared/constants' import { makePaneKey } from '../../../shared/stable-pane-id' @@ -465,86 +464,6 @@ describe('resolveAutoAckTabTargets', () => { }) }) -// Why: the minimized toggle's attention dot is the only signal a closed floating panel has, so a -// hidden panel must never auto-ack (selectFloatingWorkspaceHasUnread β†’ FloatingTerminalToggleButton). -describe('floating workspace auto-ack against the attention dot', () => { - const FLOATING_TAB_ID = 'tab-floating' - const floatingPaneKey = makePaneKey(FLOATING_TAB_ID, CODEX_LEAF_ID) - - function seedFloatingCompletion(): ReturnType { - const store = createTestStore() - store.setState({ - activeView: 'terminal', - activeTabId: 'tab-1', - activeWorktreeId: 'wt-1', - activeTabIdByWorktree: { - 'wt-1': 'tab-1', - [FLOATING_TERMINAL_WORKTREE_ID]: FLOATING_TAB_ID - }, - tabsByWorktree: { - 'wt-1': [makeTab({ id: 'tab-1', worktreeId: 'wt-1' })], - [FLOATING_TERMINAL_WORKTREE_ID]: [ - makeTab({ id: FLOATING_TAB_ID, worktreeId: FLOATING_TERMINAL_WORKTREE_ID }) - ] - } - }) - store.getState().markAgentCompletionPaneUnread(floatingPaneKey, 'agent-completion') - return store - } - - function runAutoAckScan(store: TestStore, floatingPanelVisible: boolean): void { - const state = store.getState() - for (const target of resolveAutoAckTabTargets(state, { floatingPanelVisible })) { - const current = store.getState() - const surface = createTerminalAttentionSurface(current) - const viewedUnreadSubjectKey = resolveViewedUnreadSubjectKey( - current.unreadAgentCompletionPanes, - makePaneKey(target.tabId, CODEX_LEAF_ID) - ) - const clearedSubjectKeys = new Set(viewedUnreadSubjectKey ? [viewedUnreadSubjectKey] : []) - const workspaceId = target.worktreeId - applyAgentAttentionAcknowledgement( - { - acknowledgeSubjects: current.acknowledgeAgents, - clearWorkspaceUnread: current.clearWorktreeUnread, - clearGroupUnread: current.clearTerminalTabUnread, - clearSubjectUnread: current.clearTerminalPaneUnread - }, - { - workspaceIdToClear: - workspaceId !== null && - shouldClearWorkspaceAttention(surface.collectWorkspaceAttentionRemainder(workspaceId), { - viewedGroupId: target.tabId, - clearedSubjectKeys - }) - ? workspaceId - : null, - viewedGroupId: target.tabId, - subjectKeys: [], - viewedUnreadSubjectKey - } - ) - } - } - - it('keeps the attention dot lit while the panel is closed', () => { - const store = seedFloatingCompletion() - expect(selectFloatingWorkspaceHasUnread(store.getState())).toBe(true) - - runAutoAckScan(store, false) - - expect(selectFloatingWorkspaceHasUnread(store.getState())).toBe(true) - }) - - it('clears the attention dot once the panel is visible', () => { - const store = seedFloatingCompletion() - - runAutoAckScan(store, true) - - expect(selectFloatingWorkspaceHasUnread(store.getState())).toBe(false) - }) -}) - describe('computeLapsedManualUnreadProtections', () => { const paneKey = makePaneKey('tab-1', CODEX_LEAF_ID) const otherPaneKey = makePaneKey('tab-1', OTHER_LEAF_ID) diff --git a/src/renderer/src/hooks/useIssueMetadata.test.tsx b/src/renderer/src/hooks/useIssueMetadata.test.tsx index 97f6b3d6b6c..bff14b1c091 100644 --- a/src/renderer/src/hooks/useIssueMetadata.test.tsx +++ b/src/renderer/src/hooks/useIssueMetadata.test.tsx @@ -6,8 +6,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { clearLinearMetadataCache, useRepoLabels, - useTeamLabels, - useTeamMembers, useTeamStates, useTeamsStates } from './useIssueMetadata' @@ -167,50 +165,6 @@ describe('useIssueMetadata hooks', () => { expect(renders).toBeLessThanOrEqual(4) }) - it('does not re-issue a failed team-label fetch when a fresh settings object re-renders', async () => { - let renders = 0 - let error: string | null = null - linearMocks.linearTeamLabels.mockRejectedValue(new Error('Could not connect')) - - function LabelsProbe(): null { - renders += 1 - const metadata = useTeamLabels('team-1', { activeRuntimeEnvironmentId: null }, 'ws-1') - error = metadata.error - return null - } - - renderProbe() - await flushEffects() - await flushEffects() - await flushEffects() - - expect(error).toBe('Could not connect') - expect(linearMocks.linearTeamLabels).toHaveBeenCalledTimes(1) - expect(renders).toBeLessThanOrEqual(4) - }) - - it('does not re-issue a failed team-member fetch when a fresh settings object re-renders', async () => { - let renders = 0 - let error: string | null = null - linearMocks.linearTeamMembers.mockRejectedValue(new Error('Could not connect')) - - function MembersProbe(): null { - renders += 1 - const metadata = useTeamMembers('team-1', { activeRuntimeEnvironmentId: null }, 'ws-1') - error = metadata.error - return null - } - - renderProbe() - await flushEffects() - await flushEffects() - await flushEffects() - - expect(error).toBe('Could not connect') - expect(linearMocks.linearTeamMembers).toHaveBeenCalledTimes(1) - expect(renders).toBeLessThanOrEqual(4) - }) - it('unions workflow states across every selected team (#8739)', async () => { let states: { id: string; name: string }[] = [] linearMocks.linearTeamStates.mockImplementation(async (_settings, teamId: string) => { diff --git a/src/renderer/src/hooks/usePrimarySelectionPaste.test.tsx b/src/renderer/src/hooks/usePrimarySelectionPaste.test.tsx index 5724283ae1c..5f13a9c0836 100644 --- a/src/renderer/src/hooks/usePrimarySelectionPaste.test.tsx +++ b/src/renderer/src/hooks/usePrimarySelectionPaste.test.tsx @@ -274,21 +274,6 @@ describe('usePrimarySelectionPaste', () => { expect(consumeNativePasteMock).not.toHaveBeenCalled() }) - it('does not suppress native paste when the terminal has not armed the window', async () => { - setUserAgent('Mozilla/5.0 (X11; Linux x86_64)') - consumeNativePasteMock.mockReturnValue(false) - await renderProbe() - const textarea = appendTextarea() - - let nativeBeforeInput!: Event - await act(async () => { - nativeBeforeInput = dispatchNativePasteBeforeInput(textarea) - await flushPromises() - }) - - expect(nativeBeforeInput.defaultPrevented).toBe(false) - }) - it('does not keep middle-click ownership after the gesture window expires', async () => { vi.useFakeTimers() vi.setSystemTime(1_000) diff --git a/src/renderer/src/hooks/zoom-routing.test.ts b/src/renderer/src/hooks/zoom-routing.test.ts index 4d063f2d11c..b0244ed6327 100644 --- a/src/renderer/src/hooks/zoom-routing.test.ts +++ b/src/renderer/src/hooks/zoom-routing.test.ts @@ -75,16 +75,6 @@ describe('resolveZoomTarget', () => { }) ).toBe('ui') }) - - it('routes to ui zoom for browser tabs without an active browser page', () => { - expect( - resolveZoomTarget({ - activeView: 'terminal', - activeTabType: 'browser', - activeElement: makeTarget({}) - }) - ).toBe('ui') - }) }) describe('registerZoomIpcBridge', () => { diff --git a/src/renderer/src/lib/agent-launch-caller-placement.test.ts b/src/renderer/src/lib/agent-launch-caller-placement.test.ts index 40dc46804b6..03db8a68367 100644 --- a/src/renderer/src/lib/agent-launch-caller-placement.test.ts +++ b/src/renderer/src/lib/agent-launch-caller-placement.test.ts @@ -135,20 +135,6 @@ describe('agent launch caller placement and telemetry', () => { }) }) - it('falls back to the tab-bar quick launch source when a caller names none', async () => { - const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab') - - launchAgentInNewTab({ agent: 'codex', worktreeId: 'wt-1' }) - - // Why: git-history-explain-commit is the one production call site that names no launch source, - // so it is reported as a tab-bar quick launch rather than as its own surface. - expect(queuedStartupPayload(store)?.telemetry).toEqual({ - agent_kind: 'kind:codex', - launch_source: 'tab_bar_quick_launch', - request_kind: 'new' - }) - }) - it('creates the tab before queueing its startup command', async () => { const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab') diff --git a/src/renderer/src/lib/agent-paste-draft.test.ts b/src/renderer/src/lib/agent-paste-draft.test.ts index 1cd214cca95..ca5f3930417 100644 --- a/src/renderer/src/lib/agent-paste-draft.test.ts +++ b/src/renderer/src/lib/agent-paste-draft.test.ts @@ -822,14 +822,6 @@ describe('pasteDraftWhenAgentReady', () => { expect(replaceAllCallCount).toBe(0) }) - it('keeps agent draft chunk arrays aligned with lazy chunk iteration', () => { - const content = 'before\x1b[201~afterπŸ˜€' - - expect(chunkAgentDraftPasteContent(content, 6)).toEqual([ - ...iterateAgentDraftPasteContentChunks(content, 6) - ]) - }) - it('iterates large agent draft chunks lazily', () => { const text = 'x'.repeat(128) const codePointAt = vi.spyOn(String.prototype, 'codePointAt') diff --git a/src/renderer/src/lib/ai-vault-resume-target.test.ts b/src/renderer/src/lib/ai-vault-resume-target.test.ts index b4ac2902ee9..d9857050196 100644 --- a/src/renderer/src/lib/ai-vault-resume-target.test.ts +++ b/src/renderer/src/lib/ai-vault-resume-target.test.ts @@ -292,25 +292,6 @@ describe('ai vault resume target ownership', () => { ).toBe('unknown') }) - it('blocks folder workspaces owned by runtime project groups', () => { - expect( - getAiVaultResumeWorkspaceTargetStatus( - makeState({ - folderWorkspaces: [ - { - id: 'folder-1', - projectGroupId: 'group-1', - name: 'Platform', - folderPath: '/repo/platform' - } - ], - projectGroups: [{ id: 'group-1', executionHostId: 'runtime:env-1' }] - }), - folderWorkspaceKey('folder-1') - ) - ).toBe('runtime') - }) - it('blocks mixed local and runtime folder workspace targets', () => { expect( getAiVaultResumeWorkspaceTargetStatus( diff --git a/src/renderer/src/lib/browser-cookie-import-toast.test.ts b/src/renderer/src/lib/browser-cookie-import-toast.test.ts index 0482400696c..075528ad6d4 100644 --- a/src/renderer/src/lib/browser-cookie-import-toast.test.ts +++ b/src/renderer/src/lib/browser-cookie-import-toast.test.ts @@ -158,16 +158,6 @@ describe('emitBrowserCookieImportToast', () => { ) }) - it('does not infer a partition warning from generic skipped cookies', () => { - emitBrowserCookieImportToast( - { ...summary, importedCookies: 2, skippedCookies: 1 }, - 'Imported 2 cookies.', - localExecution - ) - - expect(warningToastMock).not.toHaveBeenCalled() - }) - it('does not infer a Google warning from generic skipped cookies', () => { emitBrowserCookieImportToast( { ...summary, importedCookies: 2, skippedCookies: 1 }, diff --git a/src/renderer/src/lib/focus-terminal-tab-surface.test.ts b/src/renderer/src/lib/focus-terminal-tab-surface.test.ts index 20cf491088e..da28ad74eb3 100644 --- a/src/renderer/src/lib/focus-terminal-tab-surface.test.ts +++ b/src/renderer/src/lib/focus-terminal-tab-surface.test.ts @@ -215,50 +215,6 @@ describe('focusTerminalTabSurface', () => { expect(textarea.focus).not.toHaveBeenCalled() }) - it('does not use stale-leaf fallback while the expected layout still has multiple leaves', () => { - flushAnimationFrames() - const textarea = { focus: vi.fn() } - vi.stubGlobal('document', { - querySelector: vi.fn((selector: string) => - selector === '[data-terminal-tab-id="tab-1"]' - ? { getAttribute: () => 'mounted-leaf pending-leaf' } - : null - ), - querySelectorAll: vi.fn((selector: string) => - selector === TAB_HELPER_SELECTOR - ? { length: 1, item: () => textarea } - : { length: 0, item: () => null } - ) - }) - - focusTerminalTabSurface('tab-1', 'stale-leaf') - - expect(textarea.focus).not.toHaveBeenCalled() - }) - - it('does not focus a sibling when a stale leaf id has multiple helpers in the tab', () => { - flushAnimationFrames() - const first = { focus: vi.fn() } - const second = { focus: vi.fn() } - vi.stubGlobal('document', { - querySelector: vi.fn((selector: string) => - selector === '[data-terminal-tab-id="tab-1"]' - ? { getAttribute: () => 'new-left new-right' } - : null - ), - querySelectorAll: vi.fn((selector: string) => - selector === TAB_HELPER_SELECTOR - ? { length: 2, item: (index: number) => (index === 0 ? first : second) } - : { length: 0, item: () => null } - ) - }) - - focusTerminalTabSurface('tab-1', 'stale-leaf') - - expect(first.focus).not.toHaveBeenCalled() - expect(second.focus).not.toHaveBeenCalled() - }) - it('cancels a pending focus frame when a newer focus request starts', () => { const cancelAnimationFrame = vi.fn() vi.stubGlobal( diff --git a/src/renderer/src/lib/github-work-item-source-lookup.test.ts b/src/renderer/src/lib/github-work-item-source-lookup.test.ts index 48e78ff96dd..336583b1d6d 100644 --- a/src/renderer/src/lib/github-work-item-source-lookup.test.ts +++ b/src/renderer/src/lib/github-work-item-source-lookup.test.ts @@ -54,29 +54,6 @@ describe('GitHub source lookup routing', () => { expect(window.api.gh.workItemDetails).not.toHaveBeenCalled() }) - // Regression for #6429: a runtime-sourced details lookup must never reach the - // local Electron IPC, which rejects unregistered remote repos with - // "Access denied: unknown repository path". On main this routed through - // window.api.gh.workItemDetails and surfaced that error. - it('does not invoke the local IPC (which throws access-denied) for runtime sources', async () => { - vi.mocked(callRuntimeRpc).mockResolvedValue(null) - vi.mocked(window.api.gh.workItemDetails).mockRejectedValue( - new Error('Access denied: unknown repository path') - ) - - await expect( - lookupGitHubWorkItemDetailsForSource({ - repoPath: '/home/runtime/app', - repoId: 'renderer-repo', - sourceContext: runtimeSourceContext, - number: 42, - type: 'issue' - }) - ).resolves.toBeNull() - - expect(window.api.gh.workItemDetails).not.toHaveBeenCalled() - }) - it('uses the renderer repo id for runtime details when the source has no repo id', async () => { vi.mocked(callRuntimeRpc).mockResolvedValue(null) diff --git a/src/renderer/src/lib/keyboard-layout/detect-option-as-alt.test.ts b/src/renderer/src/lib/keyboard-layout/detect-option-as-alt.test.ts index cab6e252132..cc6f97ece28 100644 --- a/src/renderer/src/lib/keyboard-layout/detect-option-as-alt.test.ts +++ b/src/renderer/src/lib/keyboard-layout/detect-option-as-alt.test.ts @@ -28,12 +28,6 @@ describe('detectOptionAsAltFromLayoutMap', () => { expect(detectOptionAsAltFromLayoutMap(mapOf(US))).toBe('us') }) - it('classifies US International as us (same fingerprint, dead keys only)', () => { - // US-International keeps all unshifted ASCII letters and punctuation. - // Only Option-layer composition differs β€” invisible to getLayoutMap(). - expect(detectOptionAsAltFromLayoutMap(mapOf(US))).toBe('us') - }) - it('classifies UK as non-us (Backquote β†’ Β§)', () => { expect(detectOptionAsAltFromLayoutMap(mapOf({ ...US, Backquote: 'Β§' }))).toBe('non-us') }) diff --git a/src/renderer/src/lib/keyboard-layout/option-as-alt-probe.test.ts b/src/renderer/src/lib/keyboard-layout/option-as-alt-probe.test.ts index ee522e956b6..3af50308e8c 100644 --- a/src/renderer/src/lib/keyboard-layout/option-as-alt-probe.test.ts +++ b/src/renderer/src/lib/keyboard-layout/option-as-alt-probe.test.ts @@ -306,20 +306,6 @@ describe('createOptionAsAltProbe', () => { probe.dispose() }) - it('trusts the input source ID over the fingerprint even when the fingerprint says us', async () => { - // Pre-fix: the fingerprint's 'us' verdict was authoritative and the - // macOS ID was ignored, so Turkish-F (which reports US-identical on - // several keys) plus any US-like fingerprint flipped - // macOptionIsMeta=true. Now the ID overrides. - const win = makeMockWindow(US_MAP) - const probe = createOptionAsAltProbe(win as unknown as Window, { - readInputSourceId: async () => 'com.apple.keylayout.German' - }) - await probe.refresh() - expect(probe.getCurrent()).toBe('non-us') - probe.dispose() - }) - it('falls back to the fingerprint when the input-source reader returns null (non-Darwin)', async () => { const win = makeMockWindow(US_MAP) const probe = createOptionAsAltProbe(win as unknown as Window, { diff --git a/src/renderer/src/lib/launch-agent-structured-chat-guard.test.ts b/src/renderer/src/lib/launch-agent-structured-chat-guard.test.ts index 192236cbcbe..eb21a7e467f 100644 --- a/src/renderer/src/lib/launch-agent-structured-chat-guard.test.ts +++ b/src/renderer/src/lib/launch-agent-structured-chat-guard.test.ts @@ -310,28 +310,6 @@ describe('structured chat adoption guard on the launch path', () => { expect(mockCreateTab).toHaveBeenCalled() }) - it('keeps a declined Claude launch on the structured path', async () => { - const { StructuredAgentSessionCreateRefusalError } = - await import('./launch-structured-agent-session') - const refusal = new StructuredAgentSessionCreateRefusalError( - 'structured_agent_session_unsupported' - ) - mockLaunchStructuredCodexSession.mockRejectedValueOnce(refusal) - const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab') - - const result = launchAgentInNewTab({ agent: 'claude', worktreeId: 'wt-1' }) - - expect(result).toMatchObject({ - surface: { kind: 'local-agent-session', sessionId: 'codex-session-1' } - }) - await expect(result?.structuredSettlement).resolves.toEqual({ - kind: 'failed', - error: refusal - }) - expect(mockCreateTab).not.toHaveBeenCalled() - await vi.waitFor(() => expect(mockToastError).toHaveBeenCalledOnce()) - }) - it.each([[], null])( 'preserves terminal-backed launches with capability answer %s', async (capabilities) => { diff --git a/src/renderer/src/lib/lazy-with-retry.right-sidebar-syntax-error.test.ts b/src/renderer/src/lib/lazy-with-retry.right-sidebar-syntax-error.test.ts deleted file mode 100644 index f0ba64513a3..00000000000 --- a/src/renderer/src/lib/lazy-with-retry.right-sidebar-syntax-error.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -// @vitest-environment happy-dom -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' - -import { isLazyChunkLoadError, loadLazyWithRetry } from './lazy-with-retry' - -// Regression guard for crash report e08749bb-777c-446e-b407-5d1f154b6173 (Orca 1.4.104). -// boundary_id=right-sidebar, surface=right-sidebar, error_name=SyntaxError, -// error_message="Unexpected token ')'". component_stack: Lazy -> Suspense -> -// RightSidebarPanelContent -> ... -> RecoverableRenderErrorBoundary. -// -// The right-sidebar source-control panel is loaded via lazyWithRetry: -// src/renderer/src/components/right-sidebar/right-sidebar-panel-content.tsx:6 -// const SourceControl = lazy(() => import('./SourceControl')) // lazyWithRetry -// -// So the corrupt-chunk recovery IS wired in. The crash was a BLIND SPOT in that -// recovery: after the single guarded window.location.reload() has already landed -// once this session (the guard holds a *previous* document's identity), -// loadLazyWithRetry only converted the failure into a recoverable -// LazyChunkLoadError when isKnownDynamicImportFailure(error) was true. A corrupt / -// truncated chunk that parses as invalid JS rejects import() with a native -// SyntaxError whose .name is "SyntaxError" (not "ChunkLoadError") and whose -// message "Unexpected token ')'" matched NONE of the dynamic-import regexes, so -// it was re-thrown raw to the boundary and killed the right sidebar β€” the exact -// reported crash. The fix treats a parse-time SyntaxError as a recoverable -// corrupt-chunk failure; these tests pin that behavior. - -const RELOAD_GUARD_KEY = 'orca:lazy-chunk-reload-attempted' -const LANDED_RELOAD_GUARD_VALUE = 'doc-before-the-reload' - -// The exact error the renderer received from the corrupt right-sidebar chunk. -const reportedCrashError = (): SyntaxError => new SyntaxError("Unexpected token ')'") -// An equivalent transient fetch failure, for contrast β€” this one DOES recover. -const equivalentFetchError = (): TypeError => - new TypeError('Failed to fetch dynamically imported module: file://redacted/SourceControl.js') - -function spyOnReload(): ReturnType { - const reload = vi.fn() - vi.spyOn(window.location, 'reload').mockImplementation(reload) - return reload -} - -beforeEach(() => { - vi.useFakeTimers() - window.sessionStorage.clear() -}) - -afterEach(() => { - vi.unstubAllGlobals() - vi.restoreAllMocks() - vi.useRealTimers() - try { - window.sessionStorage.clear() - } catch { - // ignore - } -}) - -describe('right-sidebar lazy chunk SyntaxError crash (regression)', () => { - it('recovers a corrupt right-sidebar chunk SyntaxError instead of surfacing it to the boundary', async () => { - const reload = spyOnReload() - // The one guarded reload already landed earlier this session: the guard was - // written by the document that reloaded, not by this one. - window.sessionStorage.setItem(RELOAD_GUARD_KEY, LANDED_RELOAD_GUARD_VALUE) - - // import('./SourceControl') rejects with the native parse error from the - // corrupt chunk β€” exactly what the crash report captured. - const factory = vi.fn(() => Promise.reject(reportedCrashError())) - - const loaded = loadLazyWithRetry(factory, { retries: 2, reloadKey: 'right-sidebar' }) - // Drain the retry backoff timers first (fake timers), THEN await the result. - const settled = loaded.then( - () => null, - (error: unknown) => error - ) - await vi.advanceTimersByTimeAsync(5000) - const caught = await settled - - // A corrupt-chunk parse failure is unrecoverable-by-retry, so it must be - // wrapped as a recoverable LazyChunkLoadError, NOT re-thrown raw to the - // RecoverableRenderErrorBoundary where its only "Retry" re-runs the same dead - // import. With the fix, the parse-time SyntaxError is recovered. - expect(reload).not.toHaveBeenCalled() // guard already set: no second reload - expect(isLazyChunkLoadError(caught)).toBe(true) - }) - - it('treats the corrupt chunk SyntaxError the same as an equivalent fetch failure', async () => { - // Demonstrates the blind spot is purely error-shape gating: the SAME corrupt - // chunk, surfaced as a fetch failure, IS recovered; surfaced as a parse error, - // it is not. Both are the same unrecoverable corrupt right-sidebar chunk. - const recover = async (makeError: () => Error): Promise => { - window.sessionStorage.setItem(RELOAD_GUARD_KEY, LANDED_RELOAD_GUARD_VALUE) - const factory = vi.fn(() => Promise.reject(makeError())) - const loaded = loadLazyWithRetry(factory, { retries: 0, reloadKey: 'right-sidebar' }) - try { - await loaded - return null - } catch (error) { - return error - } finally { - await vi.advanceTimersByTimeAsync(5000) - window.sessionStorage.clear() - } - } - - spyOnReload() - const fetchOutcome = await recover(equivalentFetchError) - const parseOutcome = await recover(reportedCrashError) - - expect(isLazyChunkLoadError(fetchOutcome)).toBe(true) // recovered - // The parse error from the very same corrupt chunk must be recovered too. - expect(isLazyChunkLoadError(parseOutcome)).toBe(true) - }) -}) diff --git a/src/renderer/src/lib/native-chat-launch-draft-mirrorability.test.ts b/src/renderer/src/lib/native-chat-launch-draft-mirrorability.test.ts index 5cdc89ca936..be8b0906170 100644 --- a/src/renderer/src/lib/native-chat-launch-draft-mirrorability.test.ts +++ b/src/renderer/src/lib/native-chat-launch-draft-mirrorability.test.ts @@ -62,13 +62,6 @@ describe('launch draft mirrorability', () => { vi.clearAllMocks() }) - // Why: the whole point of the shared predicate. If either side ever grows its - // own inline rule, a draft launch opens in chat with an empty composer beside - // a filled TUI input (or stays in the terminal with a mirror nobody sees). - it.each(DRAFT_TEXTS)('opens in chat exactly when it seeds: %j', (text) => { - expect(opensInChat(text)).toBe(seedsTheComposer(text)) - }) - it.each(DRAFT_TEXTS)('both sides follow the predicate: %j', (text) => { const expected = canMirrorLaunchDraftToNativeChat(text) expect(seedsTheComposer(text)).toBe(expected) diff --git a/src/renderer/src/lib/orchestration-skill-coverage.test.ts b/src/renderer/src/lib/orchestration-skill-coverage.test.ts index d0128396e4e..8fe696caab1 100644 --- a/src/renderer/src/lib/orchestration-skill-coverage.test.ts +++ b/src/renderer/src/lib/orchestration-skill-coverage.test.ts @@ -306,77 +306,6 @@ describe('orchestration skill agent coverage', () => { ).toBe(true) }) - it('marks a multi-segment provider-home agent from a Windows-style path', () => { - expect( - agentHasOrchestrationSkill( - 'opencode', - [ - skill({ - providers: ['agent-skills'], - sourceKind: 'home', - rootPath: 'C:\\Users\\test\\.config\\opencode\\skills', - directoryPath: 'C:\\Users\\test\\.config\\opencode\\skills\\orchestration' - }) - ], - [source('C:\\Users\\test\\.config\\opencode\\skills', 'opencode')] - ) - ).toBe(true) - }) - - it('keeps Pi and OMP distinct despite sharing the /agent/skills shape', () => { - const piInstall = [ - skill({ - providers: ['agent-skills'], - sourceKind: 'home', - rootPath: '/Users/test/.pi/agent/skills', - directoryPath: '/Users/test/.pi/agent/skills/orchestration' - }) - ] - const ompInstall = [ - skill({ - providers: ['agent-skills'], - sourceKind: 'home', - rootPath: '/Users/test/.omp/agent/skills', - directoryPath: '/Users/test/.omp/agent/skills/orchestration' - }) - ] - - const piSources = [source('/Users/test/.pi/agent/skills', 'pi')] - const ompSources = [source('/Users/test/.omp/agent/skills', 'omp')] - expect(agentHasOrchestrationSkill('pi', piInstall, piSources)).toBe(true) - expect(agentHasOrchestrationSkill('omp', piInstall, piSources)).toBe(false) - expect(agentHasOrchestrationSkill('omp', ompInstall, ompSources)).toBe(true) - expect(agentHasOrchestrationSkill('pi', ompInstall, ompSources)).toBe(false) - }) - - it('keeps Gemini and Antigravity distinct despite sharing the ~/.gemini root', () => { - const geminiInstall = [ - skill({ - providers: ['agent-skills'], - sourceKind: 'home', - rootPath: '/Users/test/.gemini/skills', - directoryPath: '/Users/test/.gemini/skills/orchestration' - }) - ] - const antigravityInstall = [ - skill({ - providers: ['agent-skills'], - sourceKind: 'home', - rootPath: '/Users/test/.gemini/antigravity/skills', - directoryPath: '/Users/test/.gemini/antigravity/skills/orchestration' - }) - ] - - const geminiSources = [source('/Users/test/.gemini/skills', 'gemini')] - const antigravitySources = [source('/Users/test/.gemini/antigravity/skills', 'antigravity')] - expect(agentHasOrchestrationSkill('gemini', geminiInstall, geminiSources)).toBe(true) - expect(agentHasOrchestrationSkill('antigravity', geminiInstall, geminiSources)).toBe(false) - expect(agentHasOrchestrationSkill('antigravity', antigravityInstall, antigravitySources)).toBe( - true - ) - expect(agentHasOrchestrationSkill('gemini', antigravityInstall, antigravitySources)).toBe(false) - }) - it('marks Claude Agent Teams from ~/.claude/skills like Claude Code', () => { const skills = [ skill({ @@ -393,21 +322,4 @@ describe('orchestration skill agent coverage', () => { ]) ).toBe(true) }) - - it('marks Windows skill paths', () => { - expect( - agentHasOrchestrationSkill( - 'codex', - [ - skill({ - providers: ['codex'], - sourceKind: 'home', - rootPath: 'C:\\Users\\test\\.codex\\skills', - directoryPath: 'C:\\Users\\test\\.codex\\skills\\orchestration' - }) - ], - [source('C:\\Users\\test\\.codex\\skills', 'codex')] - ) - ).toBe(true) - }) }) diff --git a/src/renderer/src/lib/skill-freshness-display-status.test.ts b/src/renderer/src/lib/skill-freshness-display-status.test.ts index 66c616a702f..ff24aea1a83 100644 --- a/src/renderer/src/lib/skill-freshness-display-status.test.ts +++ b/src/renderer/src/lib/skill-freshness-display-status.test.ts @@ -251,16 +251,6 @@ describe('hasSkillCopyNeedingAttention', () => { ) }) - // Regression guard for the centralization: the badge predicate deliberately omits the - // shared helper's outdated carve-out, so a non-eligible outdated copy stays amber. - // Collapsing the two predicates would flip this to green while the dialog still shows - // a reinstall row β€” the badge/dialog contradiction this change exists to avoid. - it('keeps a non-eligible outdated global copy amber', () => { - expect(getSkillFreshnessDisplayStatus(inventory([placement('outdated')]), SKILL_NAME)).toBe( - 'needs-attention' - ) - }) - // Why: an unreadable plugin path could hide a copy of anything, but a skill Orca // never found anywhere is not the one to blame for it β€” that reads as a problem // with a skill the user has not installed. diff --git a/src/renderer/src/lib/structured-agent-session-launch.test.ts b/src/renderer/src/lib/structured-agent-session-launch.test.ts index 458bb08e2e4..33bbc737530 100644 --- a/src/renderer/src/lib/structured-agent-session-launch.test.ts +++ b/src/renderer/src/lib/structured-agent-session-launch.test.ts @@ -566,26 +566,6 @@ describe('startStructuredAgentLaunch', () => { expect(toast.error).toHaveBeenCalledOnce() }) - it('replays the same intent after an absent unknown outcome', async () => { - const worktreeId = 'wt-replay-unknown' - const intent = launchIntent(worktreeId) - mocks.createIntent.mockReturnValueOnce(intent) - mocks.launch - .mockRejectedValueOnce(new Error('offline')) - .mockResolvedValueOnce({ sessionId: intent.sessionId, fence: 1 }) - vi.mocked(refreshLocalStructuredSessionTabs) - .mockResolvedValueOnce([]) - .mockResolvedValueOnce([publishedSnapshot(worktreeId, intent.sessionId)]) - - startStructuredAgentLaunch(worktreeId, 'codex') - await flushLaunchSettlement() - - expect(mocks.createIntent).toHaveBeenCalledOnce() - expect(mocks.launch).toHaveBeenCalledTimes(2) - expect(mocks.launch.mock.calls[1]?.[0]).toBe(intent) - expect(toast.error).not.toHaveBeenCalled() - }) - it('reuses the queued prompt without a second delivery after unknown recovery', async () => { const worktreeId = 'wt-unknown-prompt-retry' const intent = launchIntent(worktreeId) diff --git a/src/renderer/src/lib/tui-agent-startup.test.ts b/src/renderer/src/lib/tui-agent-startup.test.ts index b4551ae8a23..7ce665544b3 100644 --- a/src/renderer/src/lib/tui-agent-startup.test.ts +++ b/src/renderer/src/lib/tui-agent-startup.test.ts @@ -310,23 +310,6 @@ describe('buildAgentStartupPlan', () => { }) ).toBeNull() }) - - it('uses -i flag for copilot to start an interactive session with initial prompt', () => { - expect( - buildAgentStartupPlan({ - agent: 'copilot', - prompt: 'Fix the bug', - cmdOverrides: {}, - platform: 'darwin' - }) - ).toEqual({ - agent: 'copilot', - launchCommand: "copilot -i 'Fix the bug'", - expectedProcess: 'copilot', - followupPrompt: null, - launchConfig: emptyLaunchConfig('copilot') - }) - }) }) describe('buildAgentDraftLaunchPlan', () => { diff --git a/src/renderer/src/lib/window-label-formatter.test.ts b/src/renderer/src/lib/window-label-formatter.test.ts index 0390f7e84a0..73954ebf505 100644 --- a/src/renderer/src/lib/window-label-formatter.test.ts +++ b/src/renderer/src/lib/window-label-formatter.test.ts @@ -18,10 +18,6 @@ describe('formatWindowLabel', () => { expect(formatWindowLabel(10080)).toBe('wk') }) - it('returns "1d" for 1440 minutes (1 day)', () => { - expect(formatWindowLabel(1440)).toBe('1d') - }) - it('returns "2h" for 120 minutes', () => { expect(formatWindowLabel(120)).toBe('2h') }) @@ -34,10 +30,6 @@ describe('formatWindowLabel', () => { expect(formatWindowLabel(20160)).toBe('2wk') }) - it('returns "30m" for 30 minutes', () => { - expect(formatWindowLabel(30)).toBe('30m') - }) - it('returns "3d" for 4320 minutes (3 days)', () => { expect(formatWindowLabel(4320)).toBe('3d') }) @@ -51,13 +43,6 @@ describe('formatWindowLabel', () => { expect(formatWindowLabel(295)).toBe('295m') expect(formatWindowLabel(300)).toBe('5h') }) - - it('falls back to per-minute labels outside canonical buckets', () => { - // Why: when the window length lands between buckets (e.g. 2h30m), we - // render the raw minute count rather than guess at a half-bucket label. - expect(formatWindowLabel(75)).toBe('75m') - expect(formatWindowLabel(150)).toBe('150m') - }) }) describe('formatRateLimitWindowChipLabel', () => { diff --git a/src/renderer/src/lib/workspace-port-host-availability.test.ts b/src/renderer/src/lib/workspace-port-host-availability.test.ts index 7652c65a21a..6ef58279b29 100644 --- a/src/renderer/src/lib/workspace-port-host-availability.test.ts +++ b/src/renderer/src/lib/workspace-port-host-availability.test.ts @@ -42,24 +42,6 @@ describe('getUnavailableWorkspacePortHosts', () => { ]) }) - it('keeps colons inside an environment id when parsing the scan key', () => { - // Why: keys are `${targetKey}:all`, so the id runs to the last `:all` β€” - // splitting on the first colon would truncate ids that contain colons. - expect( - getUnavailableWorkspacePortHosts({ - 'local:all': scan(), - 'environment:weird:id:all': scan({ unavailableReason: 'Remote connection dropped' }) - }) - ).toEqual([ - { - scanKey: 'environment:weird:id:all', - host: { kind: 'environment', environmentId: 'weird:id' }, - platform: 'linux', - reason: 'Remote connection dropped' - } - ]) - }) - // Why: total loss of contact is where naming the host matters most β€” the merged // projection joins raw internal scan keys, so it cannot name them itself. it('names every host when all of them failed', () => { @@ -84,38 +66,6 @@ describe('getUnavailableWorkspacePortHosts', () => { ]) }) - it('names a single failed host', () => { - expect( - getUnavailableWorkspacePortHosts({ - 'local:all': scan({ unavailableReason: 'lsof is unavailable' }) - }) - ).toEqual([ - { - scanKey: 'local:all', - host: { kind: 'local' }, - platform: 'linux', - reason: 'lsof is unavailable' - } - ]) - }) - - // Why: the synthetic all-hosts projection key must never be labelled as the - // local machine β€” that would blame the wrong host for a remote failure. - it('marks an unrecognised scan key as an unknown host', () => { - expect( - getUnavailableWorkspacePortHosts({ - 'all-hosts:all': scan({ unavailableReason: 'Remote connection dropped' }) - }) - ).toEqual([ - { - scanKey: 'all-hosts:all', - host: { kind: 'unknown' }, - platform: 'linux', - reason: 'Remote connection dropped' - } - ]) - }) - // Why: a paired web client's userAgent is not the Orca host's platform, so the // caller labels the local host from the scan's own platform. it("carries the failed scan's platform, and null when it is unknown", () => { diff --git a/src/renderer/src/lib/worktree-activity-state.test.ts b/src/renderer/src/lib/worktree-activity-state.test.ts index 777eeb07595..279436fa6f8 100644 --- a/src/renderer/src/lib/worktree-activity-state.test.ts +++ b/src/renderer/src/lib/worktree-activity-state.test.ts @@ -27,12 +27,6 @@ function makeAgentEntry( } describe('worktree activity state', () => { - it('treats a slept wake-hint workspace as inactive', () => { - expect( - isInactiveWorkspace('wt-1', { 'wt-1': [makeTab('tab-1')] }, { 'tab-1': [] }, {}, new Set()) - ).toBe(true) - }) - it('treats a never-opened workspace as inactive', () => { expect(isInactiveWorkspace('wt-1', {}, {}, {}, new Set())).toBe(true) }) diff --git a/src/renderer/src/lib/worktree-draft-startup-view-mode.test.ts b/src/renderer/src/lib/worktree-draft-startup-view-mode.test.ts index 360e414ff13..71d895c80af 100644 --- a/src/renderer/src/lib/worktree-draft-startup-view-mode.test.ts +++ b/src/renderer/src/lib/worktree-draft-startup-view-mode.test.ts @@ -59,11 +59,4 @@ describe('resolveBackendDraftStartup', () => { setRepoConnection('runtime-ssh-env-1') expect(viewModeFor('omp')).toBe('chat') }) - - it('preserves the same split for Grok', () => { - setRepoConnection(null) - expect(viewModeFor('grok')).toBe('chat') - setRepoConnection('ssh-target-1') - expect(viewModeFor('grok')).toBe('terminal') - }) })