diff --git a/config/flaky-test-pattern-baseline.txt b/config/flaky-test-pattern-baseline.txt
index 60a2d52bd71..12aa2ccee52 100644
--- a/config/flaky-test-pattern-baseline.txt
+++ b/config/flaky-test-pattern-baseline.txt
@@ -289,7 +289,6 @@
1 test-no-real-time-wait:src/main/wsl/orcad/wsl-orcad-stdio-bridge.test.ts
1 test-no-real-time-wait:src/renderer/src/components/UpdateCard.error-card.test.tsx
1 test-no-real-time-wait:src/renderer/src/components/activity/activity-portal-readiness-loop.react185.test.tsx
-1 test-no-real-time-wait:src/renderer/src/components/dashboard-popout/useDashboardSnapshot.test.tsx
1 test-no-real-time-wait:src/renderer/src/components/editor/DiagramViewerModal.test.tsx
1 test-no-real-time-wait:src/renderer/src/components/editor/combined-diff/load-sections/combined-diff-stale-analysis-work-budget.test.tsx
1 test-no-real-time-wait:src/renderer/src/components/native-chat/NativeChatModelCombobox.test.tsx
diff --git a/config/scripts/ci-shard-timings.json b/config/scripts/ci-shard-timings.json
index 08f5cf2d50b..902cdb31d69 100644
--- a/config/scripts/ci-shard-timings.json
+++ b/config/scripts/ci-shard-timings.json
@@ -6898,7 +6898,6 @@
"src/renderer/src/components/crash-report/crash-report-submit-notice.test.ts": 208,
"src/renderer/src/components/crash-report/use-crash-report-copy.test.tsx": 425,
"src/renderer/src/components/dashboard-popout/AgentKanbanBoard.test.tsx": 1004,
- "src/renderer/src/components/dashboard-popout/AgentKanbanCard.test.tsx": 841,
"src/renderer/src/components/dashboard-popout/AgentTerminalDialog.test.tsx": 935,
"src/renderer/src/components/dashboard-popout/AgentTerminalPreview.clipboard-routes.test.tsx": 2983,
"src/renderer/src/components/dashboard-popout/AgentTerminalPreview.frame-lifecycle.test.tsx": 2678,
@@ -6917,7 +6916,6 @@
"src/renderer/src/components/dashboard-popout/useDashboardSnapshot.test.tsx": 432,
"src/renderer/src/components/dashboard/AgentDashboardDrawer.focus.test.tsx": 2567,
"src/renderer/src/components/dashboard/AgentDashboardDrawer.test.tsx": 1981,
- "src/renderer/src/components/dashboard/DashboardAgentRow.test.tsx": 2350,
"src/renderer/src/components/dashboard/agent-dashboard-open-mode.test.ts": 48,
"src/renderer/src/components/dashboard/agent-destination-navigation.integration.test.tsx": 3232,
"src/renderer/src/components/dashboard/agent-row-lineage-model.test.ts": 107,
diff --git a/src/renderer/src/components/dashboard-popout/AgentKanbanCard.test.tsx b/src/renderer/src/components/dashboard-popout/AgentKanbanCard.test.tsx
deleted file mode 100644
index 6dac14aa918..00000000000
--- a/src/renderer/src/components/dashboard-popout/AgentKanbanCard.test.tsx
+++ /dev/null
@@ -1,366 +0,0 @@
-// @vitest-environment happy-dom
-
-import '@testing-library/jest-dom/vitest'
-import { act, cleanup, fireEvent, render, screen } from '@testing-library/react'
-import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import type { DashboardCard } from '../../../../shared/dashboard-snapshot'
-import type { RepoIcon } from '../../../../shared/repo-icon'
-import { i18n } from '@/i18n/i18n'
-import { TooltipProvider } from '@/components/ui/tooltip'
-import { AgentKanbanCard } from './AgentKanbanCard'
-
-const agentIconRender = vi.fn()
-const agentStateDotRender = vi.fn()
-
-vi.mock('@/lib/agent-catalog', () => ({
- AgentIcon: () => {
- agentIconRender()
- return
- }
-}))
-
-vi.mock('@/components/AgentStateDot', () => ({
- AgentStateDot: ({ state }: { state: string }) => {
- agentStateDotRender(state)
- return
- }
-}))
-
-function card(overrides: Partial = {}): DashboardCard {
- return {
- paneKey: 'tab:leaf',
- ptyId: 'pty-1',
- agentType: 'claude',
- bucket: 'working',
- dotState: 'working',
- task: 'Review the change',
- repoId: 'repo-1',
- worktreeId: 'worktree-1',
- tabId: 'tab',
- leafId: 'leaf',
- repoName: 'Orca',
- worktreeName: 'dashboard-review',
- startedAt: 1_000,
- finishedAt: null,
- stateChangedAt: 1_000,
- unseen: false,
- ...overrides
- }
-}
-
-function renderCard(props: {
- card: DashboardCard
- now: number
- repoIcon?: RepoIcon | null
- onOpenTerminal?: () => void
-}): ReturnType {
- return render(
-
-
-
- )
-}
-
-describe('AgentKanbanCard', () => {
- beforeEach(async () => {
- await i18n.changeLanguage('en')
- })
-
- afterEach(() => {
- cleanup()
- vi.clearAllMocks()
- })
-
- it('rerenders on a verdict-only change without a clean completion tint', () => {
- const initial = card({ dotState: 'done', bucket: 'idle' })
- const onOpenTerminal = vi.fn()
- const { container, rerender } = renderCard({ card: initial, now: 2000, onOpenTerminal })
- for (const verdict of ['interrupted', 'failed', 'unconfirmed'] as const) {
- rerender(
-
-
-
- )
- expect(agentStateDotRender).toHaveBeenLastCalledWith(verdict)
- expect(container.firstElementChild?.className).not.toContain('emerald')
- }
- })
-
- it('does not render an invented age when the start time is unknown', () => {
- renderCard({ card: card({ startedAt: 0 }), now: 2_000_000_000 })
-
- expect(screen.queryByText(/\d+d/)).not.toBeInTheDocument()
- })
-
- it('shows the question glyph once when a summary is available', () => {
- const attentionCard = card({
- bucket: 'attention',
- dotState: 'waiting',
- askSummary: 'Approve deploy?',
- verdict: 'failed'
- })
- const { container, rerender } = renderCard({ card: attentionCard, now: 2_000 })
-
- expect(screen.queryByTestId('state-dot')).not.toBeInTheDocument()
- expect(container.querySelectorAll('.lucide-message-circle-question-mark')).toHaveLength(1)
-
- rerender(
-
-
-
- )
- expect(screen.getByTestId('state-dot')).toBeInTheDocument()
- expect(container.querySelector('.lucide-message-circle-question-mark')).toBeNull()
- })
-
- it('shows the saved SSH host beside the repository metadata', () => {
- const { container } = renderCard({
- card: card({
- hostKind: 'ssh',
- executionHostId: 'ssh:opaque-target',
- hostLabel: 'openclaw'
- }),
- now: 2_000
- })
-
- expect(screen.getByLabelText('SSH host · openclaw')).toHaveAttribute(
- 'data-dashboard-host-badge',
- 'ssh'
- )
- expect(container.querySelector('.lucide-server')).toBeInTheDocument()
- })
-
- it('shows review metadata and expands grouped subagents without opening the terminal', () => {
- const onOpenTerminal = vi.fn()
- renderCard({
- card: card({
- review: { number: 11012, state: 'open' },
- subagents: [
- { id: 'child-1', name: 'Review loop', dotState: 'working' },
- { id: 'child-2', name: 'Smoke tests', dotState: 'done' }
- ]
- }),
- now: 2_000,
- onOpenTerminal
- })
-
- expect(screen.getByText('#11012')).toBeInTheDocument()
- expect(screen.getByRole('img', { name: 'Open review #11012' })).toBeInTheDocument()
- expect(screen.queryByText('Review loop')).not.toBeInTheDocument()
- fireEvent.click(screen.getByRole('button', { name: '2 subagents' }))
- expect(screen.getByText('Review loop')).toBeInTheDocument()
- expect(screen.getByText('Smoke tests')).toBeInTheDocument()
- expect(onOpenTerminal).not.toHaveBeenCalled()
- })
-
- it('opens the terminal from the footer while keeping subagent disclosure isolated', () => {
- const onOpenTerminal = vi.fn()
- renderCard({
- card: card({
- conversationName: 'Dashboard review',
- review: { number: 11042, state: 'open' },
- subagents: [{ id: 'child-1', name: 'Review loop', dotState: 'working' }]
- }),
- now: 61_000,
- onOpenTerminal
- })
-
- fireEvent.click(screen.getByText('#11042'))
- expect(onOpenTerminal).toHaveBeenCalledTimes(1)
-
- fireEvent.click(screen.getByRole('button', { name: '1 subagent' }))
- expect(onOpenTerminal).toHaveBeenCalledTimes(1)
- })
-
- it('labels one subagent accessibly and never renders a workspace-status dot', () => {
- renderCard({
- card: card({
- workspaceStatusId: 'in-review',
- workspaceStatusLabel: 'In review',
- workspaceStatusColor: 'emerald',
- subagents: [{ id: 'child-1', name: 'Review loop', dotState: 'working' }]
- }),
- now: 2_000
- })
-
- expect(screen.getByRole('button', { name: '1 subagent' })).toBeInTheDocument()
- expect(screen.queryByRole('img', { name: 'In review' })).not.toBeInTheDocument()
- })
-
- it('tints unseen Done green and keeps acknowledged Done neutral as Idle', () => {
- const { container: attention } = renderCard({
- card: card({ bucket: 'attention', dotState: 'waiting' }),
- now: 2_000
- })
- expect(attention.firstElementChild?.className).toContain('border-agent-question/40')
-
- cleanup()
- const { container: done } = renderCard({
- card: card({ bucket: 'done', dotState: 'done', unseen: true }),
- now: 2_000
- })
- expect(done.firstElementChild?.className).toContain('border-emerald-500/40')
-
- cleanup()
- const { container: idle } = renderCard({
- card: card({ bucket: 'idle', dotState: 'done', unseen: false }),
- now: 2_000
- })
- const idleClassName = idle.firstElementChild?.className ?? ''
- expect(idleClassName).toContain('border-border/60')
- expect(idleClassName).not.toContain('emerald')
- expect(idleClassName).not.toContain('agent-question')
- })
-
- it('heads the card with the conversation name and drops the worktree to the footer', () => {
- const { container } = renderCard({
- card: card({ lastUserMessage: 'ship it', conversationName: 'Sparse-checkout parser' }),
- now: 2_000
- })
-
- const cardElement = container.firstElementChild!
- const header = cardElement.querySelector('button')!.firstElementChild!
- const footer = cardElement.lastElementChild!
- expect(header).toHaveTextContent('Sparse-checkout parser')
- expect(header).not.toHaveTextContent('dashboard-review')
- expect(footer).toHaveTextContent('dashboard-review')
- expect(screen.getByText('You')).toBeInTheDocument()
- })
-
- it('heads the card with the worktree when no name resolves, without repeating it', () => {
- const { container } = renderCard({ card: card({ lastUserMessage: 'ship it' }), now: 2_000 })
-
- expect(screen.getAllByText('dashboard-review')).toHaveLength(1)
- expect(container.querySelector('button')!.firstElementChild).toHaveTextContent(
- 'dashboard-review'
- )
- })
-
- it('shows the repo as an icon labelled with its name instead of inline text', () => {
- renderCard({
- card: card(),
- now: 2_000,
- repoIcon: { type: 'emoji', emoji: '🐳' }
- })
-
- expect(screen.getByLabelText('Orca')).toBeInTheDocument()
- expect(screen.getByText('🐳')).toBeInTheDocument()
- })
-
- it('skips structured-clone rerenders until visible card data or its age changes', () => {
- const onOpenTerminal = vi.fn()
- const initial = card({
- startedAt: 1_000,
- subagents: [{ id: 'child-1', name: 'Review loop', dotState: 'working' }]
- })
- const repoIcon: RepoIcon = { type: 'lucide', name: 'Rocket' }
- const { rerender } = render(
-
-
-
- )
- expect(agentIconRender).toHaveBeenCalledTimes(1)
- expect(screen.getByText('1m')).toBeInTheDocument()
-
- // A fresh structured clone of identical data — including the repo icon.
- rerender(
-
- ({ ...subagent })) }}
- repoIcon={{ ...repoIcon }}
- now={62_000}
- onOpenTerminal={onOpenTerminal}
- />
-
- )
- expect(agentIconRender).toHaveBeenCalledTimes(1)
-
- rerender(
-
- ({ ...subagent })) }}
- repoIcon={{ ...repoIcon }}
- now={121_500}
- onOpenTerminal={onOpenTerminal}
- />
-
- )
- expect(agentIconRender).toHaveBeenCalledTimes(2)
- expect(screen.getByText('2m')).toBeInTheDocument()
- })
-
- it('rerenders when a working card enters monitoring', () => {
- const initial = card()
- const { rerender } = renderCard({ card: initial, now: 2_000 })
- expect(agentStateDotRender).toHaveBeenLastCalledWith('working')
-
- rerender(
-
-
-
- )
-
- expect(agentStateDotRender).toHaveBeenLastCalledWith('monitoring')
- })
-
- it('rerenders when the repo icon changes', () => {
- const onOpenTerminal = vi.fn()
- const initial = card({ startedAt: 1_000 })
- const { rerender } = render(
-
-
-
- )
- expect(agentIconRender).toHaveBeenCalledTimes(1)
-
- rerender(
-
-
-
- )
- expect(agentIconRender).toHaveBeenCalledTimes(2)
- })
-
- it('updates the relative age when the UI language changes', async () => {
- renderCard({ card: card({ startedAt: 1_000 }), now: 121_500 })
- expect(screen.getByText('2m')).toBeInTheDocument()
-
- await act(async () => {
- await i18n.changeLanguage('ja')
- })
-
- expect(screen.getByText('2分')).toBeInTheDocument()
- })
-})
diff --git a/src/renderer/src/components/dashboard-popout/AgentTerminalDialog.test.tsx b/src/renderer/src/components/dashboard-popout/AgentTerminalDialog.test.tsx
index 5b9d021828c..bffc3de2dd0 100644
--- a/src/renderer/src/components/dashboard-popout/AgentTerminalDialog.test.tsx
+++ b/src/renderer/src/components/dashboard-popout/AgentTerminalDialog.test.tsx
@@ -37,15 +37,6 @@ vi.mock('./AgentTerminalPreview', () => ({
)
}))
-const TERMINAL_INPUT: DashboardCardTerminalInput = {
- hostPlatform: 'win32',
- localWindowsConpty: true,
- osRelease: '10.0.22631',
- windowsShiftEnterEncoding: 'csi-u',
- ctrlEnterCsiU: false,
- kittyKeyboardAdvertised: false
-}
-
function card(overrides: Partial = {}): DashboardCard {
return {
paneKey: 'tab1:leaf1',
@@ -74,121 +65,6 @@ afterEach(() => {
// This prop is the only path carrying relayed host-input facts into the preview; omission silently falls back to client-OS routing.
describe('AgentTerminalDialog', () => {
- it("hands the card's relayed host-input profile to the preview terminal", () => {
- render(
- {}}
- onReveal={() => {}}
- />
- )
-
- expect(screen.getByTestId('preview')).toHaveAttribute(
- 'data-terminal-input',
- JSON.stringify(TERMINAL_INPUT)
- )
- })
-
- it.each([
- ['interrupted', 'Interrupted'],
- ['failed', 'Failed'],
- ['unconfirmed', 'Couldn’t confirm']
- ] as const)('keeps an acknowledged %s verdict in the terminal header', (verdict, label) => {
- const statusCard = { ...card({ dotState: 'done', bucket: 'idle', unseen: false }), verdict }
- render( {}} onReveal={() => {}} />)
- expect(screen.getByText(new RegExp(label))).toBeInTheDocument()
- })
-
- it('passes null when the card carries no profile, so the preview routes by client OS', () => {
- render( {}} onReveal={() => {}} />)
-
- expect(screen.getByTestId('preview')).toHaveAttribute('data-terminal-input', 'null')
- })
-
- it('does not claim a remote pane closed when the card carries no live pty', () => {
- render(
- {}}
- onReveal={() => {}}
- />
- )
-
- // Loss of contact with an SSH host is `unverifiable`, never `exited`.
- expect(screen.getByText(/remote session/)).toBeInTheDocument()
- expect(screen.queryByText(/pane has closed/)).not.toBeInTheDocument()
- })
-
- it('keeps a local agent openable without claiming its missing preview means closure', () => {
- render(
- {}}
- onReveal={() => {}}
- />
- )
-
- expect(screen.getByText(/No preview available/)).toBeInTheDocument()
- expect(screen.queryByText(/pane has closed/)).not.toBeInTheDocument()
- expect(screen.getByRole('button', { name: 'Open worktree' })).toBeEnabled()
- })
-
- it('labels acknowledged completions idle without review or pin controls', () => {
- render(
- {}}
- onReveal={() => {}}
- />
- )
-
- expect(screen.getByText(/Claude · Idle/)).toBeInTheDocument()
- expect(screen.queryByRole('button', { name: 'Keep visible' })).not.toBeInTheDocument()
- expect(screen.queryByRole('button', { name: 'Mark reviewed' })).not.toBeInTheDocument()
- expect(screen.getByTestId('preview')).toHaveAttribute('data-pty-id', 'pty-1')
- })
-
- it('labels unseen completions done', () => {
- render(
- {}}
- onReveal={() => {}}
- />
- )
-
- expect(screen.getByText(/Claude · Done/)).toBeInTheDocument()
- })
-
- it('preserves the execution host when revealing a colliding worktree ID', () => {
- const onReveal = vi.fn()
- render(
- {}}
- onReveal={onReveal}
- />
- )
-
- fireEvent.click(screen.getByRole('button', { name: 'Open worktree' }))
- expect(onReveal).toHaveBeenCalledWith({
- repoId: 'r1',
- worktreeId: 'w1',
- executionHostId: 'runtime:env-1',
- tabId: 'tab1',
- leafId: 'leaf1'
- })
- })
-
- it('reuses the terminal surface as a non-modal adjacent panel', () => {
- render( {}} onReveal={() => {}} />)
-
- expect(screen.getByRole('dialog', { name: 'wt' })).toHaveAttribute('data-state', 'open')
- expect(screen.getByTestId('preview')).toHaveClass('min-h-0', 'flex-1')
- expect(document.querySelector('[data-slot="dialog-overlay"]')).not.toBeInTheDocument()
- expect(screen.getByRole('heading', { name: 'wt' })).toBeInTheDocument()
- })
-
it('lets a nested Radix layer consume Escape before closing the panel', () => {
const onOpenChange = vi.fn()
render(
diff --git a/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.clipboard-routes.test.tsx b/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.clipboard-routes.test.tsx
index c96f069df24..d763c1fc533 100644
--- a/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.clipboard-routes.test.tsx
+++ b/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.clipboard-routes.test.tsx
@@ -14,7 +14,6 @@ import {
BRACKETED_PASTE_START
} from '../../../../shared/terminal/input/terminal-bracketed-paste-text'
import { dispatchAppMenuPasteEvent } from '@/lib/app-menu-paste'
-import { dispatchAppMenuSelectionAction } from '@/lib/app-menu-selection-actions'
const terminalHarness = vi.hoisted(() => ({
instances: [] as {
@@ -216,245 +215,6 @@ describe('AgentTerminalPreview clipboard routes', () => {
vi.clearAllMocks()
})
- it('claims the app-menu paste event and pastes while the preview owns focus', async () => {
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- focusInsidePreview(view.container)
-
- let claimed = false
- act(() => {
- claimed = dispatchAppMenuPasteEvent()
- })
-
- // The claim is what keeps App-level paste out of xterm's hidden textarea.
- expect(claimed).toBe(true)
- await waitFor(() => expect(terminal.paste).toHaveBeenCalledWith('clip-text'))
- expect(input).toHaveBeenCalledWith('pty-1', 'clip-text')
- })
-
- it('encodes a leading newline for a remote Windows Codex preview without submitting', async () => {
- readClipboardText.mockResolvedValueOnce('\nsecond line')
- const view = render(
-
- )
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- focusInsidePreview(view.container)
-
- act(() => {
- dispatchAppMenuPasteEvent()
- })
-
- await waitFor(() =>
- expect(input).toHaveBeenCalledWith('remote:windows-box@@pty-1', '\x1b\rsecond line')
- )
- expect(terminal.input).toHaveBeenCalledWith('\x1b\rsecond line')
- expect(terminal.paste).not.toHaveBeenCalled()
- })
-
- it('claims app-menu selection actions while the preview owns focus', async () => {
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- terminal.selectionText = 'selected text'
- const focusTarget = focusInsidePreview(view.container, 'textarea')
- focusTarget.className = 'xterm-helper-textarea'
-
- let selectAllClaimed = false
- let copyClaimed = false
- act(() => {
- selectAllClaimed = dispatchAppMenuSelectionAction('select-all')
- })
- act(() => {
- copyClaimed = dispatchAppMenuSelectionAction('copy')
- })
-
- expect(selectAllClaimed).toBe(true)
- expect(copyClaimed).toBe(true)
- expect(terminal.selectAll).toHaveBeenCalledOnce()
- await waitFor(() => expect(writeTerminalClipboardText).toHaveBeenCalledWith('selected text'))
- })
-
- it('leaves app-menu selection actions unclaimed for text controls inside the preview', async () => {
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- focusInsidePreview(view.container)
-
- let claimed = true
- act(() => {
- claimed = dispatchAppMenuSelectionAction('select-all')
- })
-
- // Unclaimed so the App-level handler performs the native selection action.
- expect(claimed).toBe(false)
- expect(terminal.selectAll).not.toHaveBeenCalled()
- })
-
- it('leaves a copy action with no terminal selection unclaimed', async () => {
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
-
- let claimed = true
- act(() => {
- claimed = dispatchAppMenuSelectionAction('copy')
- })
-
- expect(claimed).toBe(false)
- expect(writeTerminalClipboardText).not.toHaveBeenCalled()
- })
-
- it('leaves the app-menu paste event unclaimed when focus is outside the preview', async () => {
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
-
- let claimed = true
- await act(async () => {
- claimed = dispatchAppMenuPasteEvent()
- })
-
- expect(claimed).toBe(false)
- expect(readClipboardText).not.toHaveBeenCalled()
- expect(terminalHarness.instances[0]!.paste).not.toHaveBeenCalled()
- })
-
- it('stops claiming app-menu clipboard events once unmounted', async () => {
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- focusInsidePreview(view.container)
- view.unmount()
-
- expect(dispatchAppMenuPasteEvent()).toBe(false)
- expect(dispatchAppMenuSelectionAction('select-all')).toBe(false)
- })
-
- it('pastes on plain Ctrl+V on Windows, where no Edit-menu accelerator ever fires', async () => {
- platformState.value = 'win32'
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
- focusInsidePreview(view.container)
-
- const plain = new KeyboardEvent('keydown', {
- key: 'v',
- code: 'KeyV',
- ctrlKey: true,
- cancelable: true
- })
- expect(terminal.customKeyHandler!(plain)).toBe(false)
- expect(plain.defaultPrevented).toBe(true)
- await waitFor(() => expect(terminal.paste).toHaveBeenCalledWith('clip-text'))
-
- // The repeat is swallowed without a second clipboard read, and so is the keyup.
- expect(
- terminal.customKeyHandler!(
- new KeyboardEvent('keydown', { key: 'v', code: 'KeyV', ctrlKey: true, repeat: true })
- )
- ).toBe(false)
- expect(terminal.customKeyHandler!(new KeyboardEvent('keyup', { key: 'v', code: 'KeyV' }))).toBe(
- false
- )
- expect(readClipboardText).toHaveBeenCalledTimes(1)
- })
-
- it('handles the shifted paste chord on Linux', async () => {
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
- focusInsidePreview(view.container)
-
- const shifted = new KeyboardEvent('keydown', {
- key: 'V',
- code: 'KeyV',
- ctrlKey: true,
- shiftKey: true,
- cancelable: true
- })
- expect(terminal.customKeyHandler!(shifted)).toBe(false)
- expect(shifted.defaultPrevented).toBe(true)
- await waitFor(() => expect(terminal.paste).toHaveBeenCalledWith('clip-text'))
- expect(readClipboardText).toHaveBeenCalledTimes(1)
- })
-
- it('leaves plain Cmd+V to the macOS Edit-menu accelerator', async () => {
- platformState.value = 'darwin'
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
- focusInsidePreview(view.container)
-
- // macOS Cmd+V uses its native accelerator; handling it here too would paste twice.
- const plain = terminal.customKeyHandler!(
- new KeyboardEvent('keydown', { key: 'v', code: 'KeyV', metaKey: true })
- )
- expect(plain).toBe(true)
- expect(readClipboardText).not.toHaveBeenCalled()
- })
-
- it('pastes on terminal-style right-click when the setting is on', async () => {
- storeState.settings = { terminalRightClickToPaste: true }
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- focusInsidePreview(view.container)
- const host = view.container.querySelector('.origin-bottom-left')!
-
- const menuEvent = new MouseEvent('contextmenu', { bubbles: true, cancelable: true })
- act(() => {
- host.dispatchEvent(menuEvent)
- })
-
- expect(menuEvent.defaultPrevented).toBe(true)
- await waitFor(() => expect(terminal.paste).toHaveBeenCalledWith('clip-text'))
- })
-
- it('copies the selection on terminal-style right-click instead of pasting', async () => {
- storeState.settings = { terminalRightClickToPaste: true }
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- terminal.selectionText = 'selected text'
- focusInsidePreview(view.container)
- const host = view.container.querySelector('.origin-bottom-left')!
-
- act(() => {
- host.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true }))
- })
-
- await waitFor(() => expect(writeTerminalClipboardText).toHaveBeenCalledWith('selected text'))
- expect(readClipboardText).not.toHaveBeenCalled()
- })
-
- it('leaves right-click to the native menu when the setting is off', async () => {
- storeState.settings = { terminalRightClickToPaste: false }
- const view = render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- focusInsidePreview(view.container)
- const host = view.container.querySelector('.origin-bottom-left')!
-
- const menuEvent = new MouseEvent('contextmenu', { bubbles: true, cancelable: true })
- act(() => {
- host.dispatchEvent(menuEvent)
- })
-
- expect(menuEvent.defaultPrevented).toBe(false)
- expect(readClipboardText).not.toHaveBeenCalled()
- })
-
it('cancels an async paste when the preview loses focus', async () => {
let resolveClipboard!: (text: string) => void
readClipboardText.mockReturnValueOnce(
diff --git a/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-geometry.test.tsx b/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-geometry.test.tsx
index 02a39386e39..81077749fe7 100644
--- a/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-geometry.test.tsx
+++ b/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-geometry.test.tsx
@@ -158,74 +158,6 @@ async function settleGeometry(): Promise {
})
}
-it.each([
- {
- updates: { terminalFontSize: 18 },
- cols: 50,
- rows: 15,
- scale: 'scale(0.625)',
- anchor: 'top left'
- },
- {
- updates: { terminalFontFamily: 'Fira Code' },
- cols: 50,
- rows: 15,
- scale: 'scale(0.625)',
- anchor: 'top left'
- },
- {
- updates: { terminalFontWeight: 900 },
- cols: 50,
- rows: 15,
- scale: 'scale(0.625)',
- anchor: 'top left'
- },
- {
- updates: { terminalFontWeightBold: 900 },
- cols: 50,
- rows: 15,
- scale: 'scale(0.625)',
- anchor: 'top left'
- },
- {
- updates: { terminalLineHeight: 1.5 },
- cols: 60,
- rows: 10,
- scale: 'scale(0.75)',
- anchor: 'bottom left'
- },
- {
- updates: { terminalLigatures: 'on' },
- cols: 60,
- rows: 15,
- scale: 'scale(0.75)',
- anchor: 'top left'
- }
-] satisfies {
- updates: Partial
- cols: number
- rows: number
- scale: string
- anchor: string
-}[])(
- 'recreates the owner and fits the new geometry for $updates',
- async ({ updates, cols, rows, scale, anchor }) => {
- render()
- await settleGeometry()
- expect(fit).toHaveBeenLastCalledWith('pty-1', 60, 15)
- await act(async () => useAppStore.getState().updateSettings(updates))
- await settleGeometry()
-
- expect(fit).toHaveBeenCalledTimes(2)
- expect(fit).toHaveBeenLastCalledWith('pty-1', cols, rows)
- expect(harness.instances).toHaveLength(2)
- expect(connect).toHaveBeenCalledTimes(2)
- expect(unsubscribe).toHaveBeenCalledExactlyOnceWith('pty-1')
- expect(harness.instances[1]?.container?.style.transform).toBe(scale)
- expect(harness.instances[1]?.container?.style.transformOrigin).toBe(anchor)
- }
-)
-
it('ignores a pending connection retired by a metric change', async () => {
const gate = Promise.withResolvers()
connect.mockReturnValueOnce(gate.promise)
diff --git a/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-lifetime.test.tsx b/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-lifetime.test.tsx
index 35f2669f083..0a1f31b7705 100644
--- a/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-lifetime.test.tsx
+++ b/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-lifetime.test.tsx
@@ -6,7 +6,7 @@ import type { ITerminalOptions } from '@xterm/xterm'
import type { GlobalSettings } from '../../../../shared/global-settings-types'
import type { TerminalPreviewConnectResult } from '../../../../shared/terminal/replay/terminal-preview'
import { createGlobalSettingsFixture } from '../../../../shared/global-settings-test-fixture'
-import { makeCustomTerminalThemeSelection } from '../../../../shared/terminal-themes/terminal-custom-themes'
+
import { useAppStore } from '@/store'
import { AgentTerminalPreview } from './AgentTerminalPreview'
@@ -79,17 +79,13 @@ const initial = useAppStore.getInitialState()
const connect = vi.fn()
const unsubscribe = vi.fn(async () => {})
const offData = vi.fn()
-const onData = vi.fn((listener: Parameters[0]) => {
- emitData = listener
- return offData
-})
+const onData = vi.fn(() => offData)
const connection: TerminalPreviewConnectResult = {
snapshot: { data: 'agent prompt', cols: 80, rows: 24, seq: 1 },
replay: []
}
let settings: GlobalSettings
let originalApi: PropertyDescriptor | undefined
-let emitData: Parameters[0] | undefined
async function updateSettings(updates: Partial): Promise {
await act(async () => useAppStore.getState().updateSettings(updates))
@@ -107,7 +103,6 @@ beforeEach(() => {
vi.clearAllMocks()
harness.instances.length = 0
harness.systemPrefersDark = false
- emitData = undefined
settings = createGlobalSettingsFixture({ theme: 'dark', activeRuntimeEnvironmentId: null })
connect.mockReset().mockResolvedValue(connection)
originalApi = Object.getOwnPropertyDescriptor(window, 'api')
@@ -158,80 +153,6 @@ describe('preview terminal settings lifetime', () => {
expect(unsubscribe).not.toHaveBeenCalled()
})
- it('updates cursor options on the existing terminal', async () => {
- render()
- await act(async () => {})
- await updateSettings({
- terminalCursorStyle: 'bar',
- terminalCursorBlink: false
- })
- expect(connect).toHaveBeenCalledOnce()
- expect(terminal().options).toMatchObject({
- cursorStyle: 'bar',
- cursorBlink: false
- })
- })
-
- it.each([
- { terminalThemeDark: 'Builtin Tango Light' },
- { terminalColorOverrides: { background: '#123456' } },
- { terminalBackgroundOpacity: 0.5 },
- { terminalCursorOpacity: 0.5 },
- { terminalMinimumContrastRatio: 7 }
- ] satisfies Partial[])(
- 'replaces the terminal when theme or contrast changes: %o',
- async (updates) => {
- render()
- await act(async () => {})
- await updateSettings(updates)
- expect(connect).toHaveBeenCalledTimes(2)
- expect(unsubscribe).toHaveBeenCalledExactlyOnceWith('pty-1')
- expect(terminal().dispose).toHaveBeenCalledOnce()
- expect(harness.instances).toHaveLength(2)
- if ('terminalMinimumContrastRatio' in updates) {
- expect(terminal(1).options.minimumContrastRatio).toBe(7)
- } else {
- expect(terminal(1).options.theme).not.toEqual(terminal().options.theme)
- }
- }
- )
-
- it('keeps a cloned imported theme but reconnects when its selected colors change', async () => {
- const custom = {
- id: 'manual:preview',
- name: 'Preview',
- source: 'manual' as const,
- mode: 'dark' as const,
- terminal: { background: '#123456', foreground: '#eeeeee', red: '#ff0000' },
- importedAt: '2026-09-25'
- }
- await updateSettings({
- terminalCustomThemes: [custom],
- terminalThemeDark: makeCustomTerminalThemeSelection(custom.id)
- })
- render()
- await act(async () => {})
- expect(terminal().options.theme?.background).toBe('#123456')
- await updateSettings({ editorAutoSaveDelayMs: 1234 })
- expect(connect).toHaveBeenCalledOnce()
- await updateSettings({
- terminalCustomThemes: [{ ...custom, terminal: { ...custom.terminal, background: '#654321' } }]
- })
- expect(connect).toHaveBeenCalledTimes(2)
- expect(terminal(1).options.theme?.background).toBe('#654321')
- })
-
- it('reconnects when the effective OS theme changes', async () => {
- await updateSettings({ theme: 'system' })
- const view = render()
- await act(async () => {})
- harness.systemPrefersDark = true
- view.rerender()
- await act(async () => {})
- expect(connect).toHaveBeenCalledTimes(2)
- expect(terminal(1).options.theme).not.toEqual(terminal().options.theme)
- })
-
it('uses current live options when an unrelated update arrives during connect', async () => {
const gate = Promise.withResolvers()
connect.mockReturnValueOnce(gate.promise)
@@ -243,18 +164,6 @@ describe('preview terminal settings lifetime', () => {
expect(terminal().options.cursorStyle).toBe('bar')
})
- it('ignores an old pending connection after a relevant theme change', async () => {
- const gate = Promise.withResolvers()
- connect.mockReturnValueOnce(gate.promise)
- render()
- await updateSettings({ terminalMinimumContrastRatio: 7 })
- expect(connect).toHaveBeenCalledTimes(2)
- expect(harness.instances).toHaveLength(1)
- await act(async () => gate.resolve(connection))
- expect(harness.instances).toHaveLength(1)
- expect(terminal().options.minimumContrastRatio).toBe(7)
- })
-
it('does not install a terminal after unmounting a pending connection', async () => {
const gate = Promise.withResolvers()
connect.mockReturnValueOnce(gate.promise)
@@ -266,27 +175,4 @@ describe('preview terminal settings lifetime', () => {
expect(connect).toHaveBeenCalledOnce()
expect(unsubscribe).toHaveBeenCalledExactlyOnceWith('ssh:host@@pty-1')
})
-
- it('keeps a hidden mounted preview connected through unrelated settings updates', async () => {
- render(
-
- )
- await act(async () => {})
- await updateSettings({ editorAutoSaveDelayMs: 1234 })
- expect(connect).toHaveBeenCalledOnce()
- expect(unsubscribe).not.toHaveBeenCalled()
- })
-
- it('still resyncs the same terminal after unrelated settings updates', async () => {
- render()
- await act(async () => {})
- await updateSettings({ editorAutoSaveDelayMs: 1234 })
- await act(async () => emitData?.({ type: 'resync', ptyId: 'pty-1' }))
- expect(connect).toHaveBeenCalledTimes(2)
- expect(harness.instances).toHaveLength(1)
- expect(terminal().reset).toHaveBeenCalledOnce()
- expect(unsubscribe).not.toHaveBeenCalled()
- })
})
diff --git a/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx b/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx
index 26fb3fd733f..6a4fd30a905 100644
--- a/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx
+++ b/src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx
@@ -253,277 +253,6 @@ describe('AgentTerminalPreview', () => {
expect(ack).toHaveBeenCalledWith('pty-1', 4)
})
- it('installs the macOS IME native-text forwarder and lets its claims bypass chord handling', async () => {
- platformState.value = 'darwin'
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
- expect(imeHarness.forwarders).toHaveLength(1)
- expect(imeHarness.trackers).toHaveLength(1)
-
- imeHarness.forwarders[0]!.sendInput('。')
- expect(terminal.input).toHaveBeenCalledOnce()
- expect(input).toHaveBeenCalledOnce()
- expect(input).toHaveBeenCalledWith('pty-1', '。')
-
- // A claimed native-text key bypasses xterm AND the clipboard chords.
- imeHarness.claimResult = true
- terminal.selectionText = 'selected text'
- const handled = terminal.customKeyHandler!(
- new KeyboardEvent('keydown', { key: 'C', code: 'KeyC', ctrlKey: true, shiftKey: true })
- )
- expect(handled).toBe(false)
- expect(writeClipboardText).not.toHaveBeenCalled()
- expect(writeTerminalClipboardText).not.toHaveBeenCalled()
-
- // Unclaimed events still reach the chord handling.
- imeHarness.claimResult = false
- const copied = terminal.customKeyHandler!(
- new KeyboardEvent('keydown', { key: 'c', code: 'KeyC', metaKey: true })
- )
- expect(copied).toBe(false)
- expect(writeTerminalClipboardText).toHaveBeenCalledWith('selected text')
- expect(writeClipboardText).not.toHaveBeenCalled()
- })
-
- it('does not install the IME native-text forwarder on Windows', async () => {
- platformState.value = 'win32'
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- await waitFor(() => expect(terminalHarness.instances[0]!.customKeyHandler).not.toBeNull())
- expect(imeHarness.forwarders).toHaveLength(0)
- expect(imeHarness.trackers).toHaveLength(0)
- })
-
- // fcitx4 delivers a single-character pick as the Space/digit keypress's text (#28213).
- it('installs the IME native-text forwarder on desktop Linux', async () => {
- platformState.value = 'linux'
- render()
- await waitFor(() => expect(imeHarness.forwarders).toHaveLength(1))
- })
-
- it('hands the forwarder the live mirror seeded from the snapshot flags', async () => {
- platformState.value = 'darwin'
- connect.mockResolvedValue({
- snapshot: { data: '', cols: 80, rows: 24, seq: 1, kittyKeyboardFlags: 8 },
- replay: []
- })
- render()
- await waitFor(() => expect(imeHarness.forwarders).toHaveLength(1))
- await waitFor(() => expect(imeHarness.forwarders[0]!.getKittyKeyboardFlags()).toBe(8))
- // The popout xterm gets the same flags, so its encoder agrees with the mirror.
- expect(terminalHarness.instances[0]!.write).toHaveBeenCalledWith(
- '\x1b[<99u\x1b[=8u',
- expect.any(Function)
- )
-
- // Live output keeps advancing the same mirror the forwarder reads.
- act(() => {
- emitData?.({ type: 'data', ptyId: 'pty-1', data: '\x1b[ {
- platformState.value = 'darwin'
- const view = render()
- await waitFor(() => expect(imeHarness.forwarders).toHaveLength(1))
- view.unmount()
- expect(imeHarness.forwarders[0]!.dispose).toHaveBeenCalledTimes(1)
- expect(imeHarness.trackers[0]!.dispose).toHaveBeenCalledTimes(1)
- })
-
- it('disposes the IME bridge once when the PTY disappears', async () => {
- platformState.value = 'darwin'
- connect.mockResolvedValueOnce({
- snapshot: { data: '', cols: 80, rows: 24, seq: 1 },
- replay: []
- })
- connect.mockResolvedValueOnce({ snapshot: null, replay: [] })
- const view = render()
- await waitFor(() => expect(imeHarness.forwarders).toHaveLength(1))
-
- act(() => emitData?.({ type: 'resync', ptyId: 'pty-1' }))
- await waitFor(() => expect(imeHarness.forwarders[0]!.dispose).toHaveBeenCalledOnce())
- expect(imeHarness.trackers[0]!.dispose).toHaveBeenCalledOnce()
-
- view.unmount()
- expect(imeHarness.forwarders[0]!.dispose).toHaveBeenCalledOnce()
- expect(imeHarness.trackers[0]!.dispose).toHaveBeenCalledOnce()
- })
-
- it('copies the terminal selection on the copy chord and blocks xterm handling', async () => {
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- terminal.selectionText = 'selected text'
- const keydown = new KeyboardEvent('keydown', {
- key: 'C',
- code: 'KeyC',
- ctrlKey: true,
- shiftKey: true,
- cancelable: true
- })
- const handled = terminal.customKeyHandler!(keydown)
- const keyupHandled = terminal.customKeyHandler!(
- new KeyboardEvent('keyup', { key: 'C', code: 'KeyC', ctrlKey: true, shiftKey: true })
- )
- expect(handled).toBe(false)
- expect(keyupHandled).toBe(false)
- expect(keydown.defaultPrevented).toBe(true)
- expect(writeTerminalClipboardText).toHaveBeenCalledWith('selected text')
- expect(writeClipboardText).not.toHaveBeenCalled()
- })
-
- it('keeps an empty copy chord from leaking terminal input', async () => {
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- const handled = terminal.customKeyHandler!(
- new KeyboardEvent('keydown', { key: 'C', code: 'KeyC', ctrlKey: true, shiftKey: true })
- )
- expect(handled).toBe(false)
- expect(writeTerminalClipboardText).not.toHaveBeenCalled()
- })
-
- it('leaves bare Ctrl+C available to the terminal without a selection', async () => {
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- const handled = terminal.customKeyHandler!(
- new KeyboardEvent('keydown', { key: 'c', code: 'KeyC', ctrlKey: true })
- )
- expect(handled).toBe(true)
- expect(writeTerminalClipboardText).not.toHaveBeenCalled()
- })
-
- it('hands unselected Cmd+C to a kitty app and copies a selection instead', async () => {
- platformState.value = 'darwin'
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
- const cmdC = (type: string): KeyboardEvent =>
- new KeyboardEvent(type, { key: 'c', code: 'KeyC', metaKey: true, cancelable: true })
-
- // A plain shell's unselected Cmd+C sends nothing.
- expect(terminal.customKeyHandler!(cmdC('keydown'))).toBe(false)
- expect(terminal.customKeyHandler!(cmdC('keyup'))).toBe(false)
-
- act(() => {
- emitData?.({ type: 'data', ptyId: 'pty-1', data: '\x1b[>1u', bytes: 5 })
- })
- expect(terminal.customKeyHandler!(cmdC('keydown'))).toBe(true)
- expect(terminal.customKeyHandler!(cmdC('keyup'))).toBe(true)
-
- // A highlight of blank cells copies no text but is still Orca's selection, as in the pane.
- Object.assign(terminal, { hasSelection: () => true })
- expect(terminal.customKeyHandler!(cmdC('keydown'))).toBe(false)
- expect(terminal.customKeyHandler!(cmdC('keyup'))).toBe(false)
- expect(writeTerminalClipboardText).not.toHaveBeenCalled()
-
- terminal.selectionText = 'selected text'
- expect(terminal.customKeyHandler!(cmdC('keydown'))).toBe(false)
- expect(terminal.customKeyHandler!(cmdC('keyup'))).toBe(false)
- expect(writeTerminalClipboardText).toHaveBeenCalledWith('selected text')
- })
-
- it('selects all terminal text on Cmd+A and blocks xterm handling', async () => {
- platformState.value = 'darwin'
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- const keydown = new KeyboardEvent('keydown', {
- key: 'a',
- code: 'KeyA',
- metaKey: true,
- cancelable: true
- })
- expect(terminal.customKeyHandler!(keydown)).toBe(false)
- expect(keydown.defaultPrevented).toBe(true)
-
- const repeat = new KeyboardEvent('keydown', {
- key: 'a',
- code: 'KeyA',
- metaKey: true,
- repeat: true,
- cancelable: true
- })
- expect(terminal.customKeyHandler!(repeat)).toBe(false)
- expect(repeat.defaultPrevented).toBe(true)
- expect(terminal.selectAll).toHaveBeenCalledOnce()
- })
-
- it('sends the word-kill byte on Ctrl+Backspace and blocks xterm handling', async () => {
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- const keydown = new KeyboardEvent('keydown', {
- key: 'Backspace',
- code: 'Backspace',
- ctrlKey: true,
- cancelable: true
- })
- const handled = terminal.customKeyHandler!(keydown)
-
- expect(handled).toBe(false)
- expect(keydown.defaultPrevented).toBe(true)
- expect(terminal.input).toHaveBeenCalledWith('\x17')
- await waitFor(() => expect(input).toHaveBeenCalledWith('pty-1', '\x17'))
- })
-
- it('swallows a pane-scoped chord instead of leaking its control byte to the agent', async () => {
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- // Ctrl+Shift+D splits a pane on Linux; xterm would otherwise send Ctrl+D.
- const keydown = new KeyboardEvent('keydown', {
- key: 'D',
- code: 'KeyD',
- ctrlKey: true,
- shiftKey: true,
- cancelable: true
- })
- const handled = terminal.customKeyHandler!(keydown)
-
- expect(handled).toBe(false)
- expect(keydown.defaultPrevented).toBe(true)
- expect(terminal.input).not.toHaveBeenCalled()
- expect(input).not.toHaveBeenCalled()
- })
-
- it('dismisses the hosting dialog on the pane-close chord', async () => {
- const onRequestClose = vi.fn()
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- const keydown = new KeyboardEvent('keydown', {
- key: 'w',
- code: 'KeyW',
- ctrlKey: true,
- cancelable: true
- })
- expect(terminal.customKeyHandler!(keydown)).toBe(false)
- expect(keydown.defaultPrevented).toBe(true)
- expect(onRequestClose).toHaveBeenCalledOnce()
- expect(input).not.toHaveBeenCalled()
- })
-
it('keeps a native input-source chord from inserting text into the preview', async () => {
storeState.keybindings = { 'terminal.switchInputSource': ['Shift+Space'] }
const view = render()
@@ -573,27 +302,6 @@ describe('AgentTerminalPreview', () => {
view.unmount()
})
- it('defers Option chords to xterm once the TUI negotiates kitty keyboard mode', async () => {
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- const altBackspace = (): KeyboardEvent =>
- new KeyboardEvent('keydown', { key: 'Backspace', code: 'Backspace', altKey: true })
- expect(terminal.customKeyHandler!(altBackspace())).toBe(false)
- expect(terminal.input).toHaveBeenCalledWith('\x1b\x7f')
-
- // The agent's TUI pushes kitty flags (CSI > 1 u) on the live stream.
- act(() => {
- emitData?.({ type: 'data', ptyId: 'pty-1', data: '\x1b[>1u', bytes: 5 })
- })
- terminal.input.mockClear()
-
- expect(terminal.customKeyHandler!(altBackspace())).toBe(true)
- expect(terminal.input).not.toHaveBeenCalled()
- })
-
// Snapshot replay can redeliver a kitty push; it must not leave stale flags after the TUI’s single pop.
it('does not let a redelivered kitty push outlive the TUI pop', async () => {
connect.mockResolvedValueOnce({
@@ -618,36 +326,6 @@ describe('AgentTerminalPreview', () => {
expect(terminal.input).toHaveBeenCalledWith('\x1b\x7f')
})
- it('scrolls the viewport on the macOS scrollback chord', async () => {
- platformState.value = 'darwin'
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- const handled = terminal.customKeyHandler!(
- new KeyboardEvent('keydown', { key: 'ArrowUp', code: 'ArrowUp', metaKey: true })
- )
-
- expect(handled).toBe(false)
- expect(terminal.scrollToTop).toHaveBeenCalled()
- expect(terminal.input).not.toHaveBeenCalled()
- })
-
- it('leaves an unmodified Backspace to xterm', async () => {
- render()
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- await waitFor(() => expect(terminal.customKeyHandler).not.toBeNull())
-
- const handled = terminal.customKeyHandler!(
- new KeyboardEvent('keydown', { key: 'Backspace', code: 'Backspace', cancelable: true })
- )
-
- expect(handled).toBe(true)
- expect(terminal.input).not.toHaveBeenCalled()
- })
-
it('keeps the existing terminal visible while a resync snapshot is captured', async () => {
let resolveRefresh!: (value: TerminalPreviewConnectResult) => void
connect
@@ -704,56 +382,6 @@ describe('AgentTerminalPreview', () => {
expect(unsubscribe).toHaveBeenCalledWith('pty-1')
})
- it('does not claim a remote pane closed when no snapshot can exist for it', async () => {
- connect.mockResolvedValueOnce({ snapshot: null, replay: [] })
- const view = render()
-
- await waitFor(() => expect(view.getByText(/remote session/)).toBeInTheDocument())
- expect(view.queryByText(/pane has closed/)).not.toBeInTheDocument()
- })
-
- it('connects a replacement pty after the previous pty was gone', async () => {
- connect.mockResolvedValueOnce({ snapshot: null, replay: [] }).mockResolvedValueOnce({
- snapshot: { data: 'replacement', cols: 80, rows: 24, seq: 1 },
- replay: []
- })
- const view = render()
- await waitFor(() => expect(view.getByText(/No preview available/)).toBeInTheDocument())
-
- view.rerender()
-
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- expect(connect).toHaveBeenLastCalledWith('pty-live', { scrollbackRows: 24 })
- expect(view.queryByText(/No preview available/)).not.toBeInTheDocument()
- })
-
- it('claims a grid sized to the dialog box and never re-requests an unchanged target', async () => {
- vi.useFakeTimers()
- const view = render()
- await vi.waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
-
- const host = view.container.querySelector('.origin-bottom-left')!
- const box = host.parentElement!
- Object.defineProperty(box, 'clientWidth', { configurable: true, value: 900 })
- Object.defineProperty(box, 'clientHeight', { configurable: true, value: 480 })
- // 80×24 grid rendered at 800×384 → 10×16 cells → the box holds 90×30.
- const screen = document.createElement('div')
- screen.className = 'xterm-screen'
- Object.defineProperty(screen, 'offsetWidth', { configurable: true, value: 800 })
- Object.defineProperty(screen, 'offsetHeight', { configurable: true, value: 384 })
- host.appendChild(screen)
-
- await vi.advanceTimersByTimeAsync(200)
- expect(fit).toHaveBeenCalledTimes(1)
- expect(fit).toHaveBeenCalledWith('pty-1', 90, 30)
-
- // Unchanged target geometry must not reclaim the grid on reconnect and fight the host.
- act(() => emitData?.({ type: 'resync', ptyId: 'pty-1' }))
- await vi.waitFor(() => expect(connect).toHaveBeenCalledTimes(2))
- await vi.advanceTimersByTimeAsync(400)
- expect(fit).toHaveBeenCalledTimes(1)
- })
-
it('delays repeated capture after an overflow and cancels the retry on unmount', async () => {
vi.useFakeTimers()
connect.mockResolvedValue({
@@ -777,40 +405,4 @@ describe('AgentTerminalPreview', () => {
await vi.advanceTimersByTimeAsync(150)
expect(connect).toHaveBeenCalledTimes(2)
})
-
- it("previews a paired host's pane from that host, not this app's main process", async () => {
- render()
-
- await waitFor(() => expect(multiplexerHarness.subscriptions).toHaveLength(1))
- expect(multiplexerHarness.environments).toEqual(['env-1'])
- expect(multiplexerHarness.subscriptions[0]!.terminal).toBe('term-7')
- expect(connect).not.toHaveBeenCalled()
-
- act(() =>
- multiplexerHarness.subscriptions[0]!.callbacks.onSnapshot('agent screen', {
- cols: 100,
- rows: 30,
- seq: 5
- })
- )
- await waitFor(() => expect(terminalHarness.instances).toHaveLength(1))
- const terminal = terminalHarness.instances[0]!
- expect(terminal.write).toHaveBeenCalledWith('agent screen', expect.any(Function))
-
- act(() => multiplexerHarness.subscriptions[0]!.callbacks.onData('live', { seq: 9 }))
- expect(terminal.write).toHaveBeenCalledWith('live', expect.any(Function))
- act(() => {
- terminalHarness.userInputListener?.()
- terminal.onDataListener?.('y')
- })
- expect(multiplexerHarness.sendInput).toHaveBeenCalledWith('y')
- })
-
- it('shows the unavailable message instead of a blank dialog when the bridge is missing', async () => {
- // The web client's fallback proxy resolves every missing bridge call to undefined.
- Object.assign(window.api.terminalPreview, { connect: async () => undefined })
- const view = render()
-
- await waitFor(() => expect(view.getByText(/No preview available/)).toBeInTheDocument())
- })
})
diff --git a/src/renderer/src/components/dashboard-popout/dashboard-preview-link-composition.test.tsx b/src/renderer/src/components/dashboard-popout/dashboard-preview-link-composition.test.tsx
index cfce43fa7ec..91e6f13d874 100644
--- a/src/renderer/src/components/dashboard-popout/dashboard-preview-link-composition.test.tsx
+++ b/src/renderer/src/components/dashboard-popout/dashboard-preview-link-composition.test.tsx
@@ -16,12 +16,11 @@ import {
mountPreviewLinkInteraction
} from './dashboard-preview-dom-test-fixture'
import { verifyPreviewLinkPopulation } from './dashboard-preview-link-population-test-fixture'
-import { verifyPopoutDefaultLinkPath } from './dashboard-preview-popout-default-test-fixture'
-import { Terminal } from '@xterm/xterm'
+
import { toast } from 'sonner'
import { runtimeStatuses } from '@/store/slices/browser-slice-test-harness'
-import { openStandaloneTerminal } from '../standalone-terminal/open-standalone-terminal'
-import { TerminalKittyKeyboardModeTracker } from '../../../../shared/terminal/protocol/input-modes/terminal-kitty-keyboard-mode-tracker'
+import type { openStandaloneTerminal } from '../standalone-terminal/open-standalone-terminal'
+
import { getDefaultSettings } from '../../../../shared/constants'
import { createStoreCascadesMockApi } from '@/store/slices/store-cascades-test-harness'
import {
@@ -37,8 +36,7 @@ import { openWorkspaceBrowserTabForLink } from '@/lib/workspace-browser-tab-open
import { AgentTerminalPreview } from './AgentTerminalPreview'
import { terminalPreviewApiFor } from './terminal-preview-api'
import { AgentKanbanBoard } from './AgentKanbanBoard'
-import { AgentTerminalPanel } from './AgentTerminalDialog'
-import { handleTerminalHttpLink } from '@/components/terminal-pane/terminal-url-link-hit-testing'
+
import type { DashboardCard } from '../../../../shared/dashboard-snapshot'
import type { GlobalSettings } from '../../../../shared/global-settings-types'
import type { ExecutionHostId } from '../../../../shared/execution-host'
@@ -214,42 +212,6 @@ async function output(data: string, ptyId = 'pty-1') {
}
const osc = `\x1b]8;;${URL_TO_OPEN}\x07hidden label\x1b]8;;\x07`
-it('uses the real Dashboard constructor, OSC primer/provider and genuine claim; context Copy and live destinations share the same URI', async () => {
- const foreground = vi.fn()
- const view = render(
-
- )
- await waitFor(() => screenFor(view.container))
- await output(`\x1b[?1000h\x1b[?1006h${osc}`)
- const screen = screenFor(view.container)
- // No hover is delivered: actual capture priming must discover the hidden OSC label.
- pointer(screen, 'mousedown')
- pointer(screen, 'mouseup')
- await waitFor(() => expect(document.querySelector('[data-link-action-popover]')).not.toBeNull())
- expect(document.querySelector('[data-terminal-link-destination]')?.textContent).toBe(URL_TO_OPEN)
- expect(
- input.mock.calls.flatMap(([, data]) => data).filter((data) => data.startsWith('\x1b[<'))
- ).toEqual([])
- fireEvent.click(view.getByRole('button', { name: 'Copy link' }))
- await waitFor(() => expect(window.api.ui.writeClipboardText).toHaveBeenCalledWith(URL_TO_OPEN))
- fireEvent.click(view.getByRole('button', { name: /System Browser/ }))
- await waitFor(() => expect(openUrl).toHaveBeenCalledWith(URL_TO_OPEN))
- expect(foreground).not.toHaveBeenCalled()
-
- store.setState((state) => ({ settings: { ...state.settings!, openLinksInApp: true } }))
- view.rerender(
-
- )
- pointer(screen, 'mousemove')
- pointer(screen, 'contextmenu', { button: 2, buttons: 0 })
- await waitFor(() => expect(view.getByRole('button', { name: /Orca Browser/ })).toBeTruthy())
- fireEvent.click(view.getByRole('button', { name: /Orca Browser/ }))
- await waitFor(() => expect(foreground).toHaveBeenCalledOnce())
- expect(store.getState().browserPagesByWorkspace).not.toEqual({})
- view.unmount()
- expect(document.querySelector('[data-link-action-popover]')).toBeNull()
-})
-
it.each(['actions', 'open'] as const)(
'retains the provider-owned hidden OSC target across unrelated live row output for %s and context',
async (behavior) => {
@@ -319,56 +281,6 @@ function seedRemoteWorkspace(
}))
}
-it.each([false, true])(
- 'keeps paired SSH OSC actions system-only with exact Copy despite the in-app preference (streaming=%s)',
- async (streaming) => {
- const hostId = 'ssh:private-target'
- const ptyId = 'remote:hub-a@@handle-1'
- const linkSource = {
- ...source,
- executionHostId: hostId,
- ptyId
- } satisfies DashboardPreviewLinkSource
- const foreground = vi.fn()
- seedRemoteWorkspace(hostId, 'hub-a', streaming)
- const props = { ptyId, linkSource, onBrowserForeground: foreground }
- const connect = vi.spyOn(terminalPreviewApiFor(ptyId), 'connect')
- const view = render()
- await waitFor(() => screenFor(view.container))
- await output(osc, ptyId)
- const screen = screenFor(view.container)
- pointer(screen, 'mousedown')
- pointer(screen, 'mouseup')
- const system = await view.findByRole('button', { name: /System Browser/ })
- expect(view.queryByRole('button', { name: /Orca Browser|Open in new tab/ })).toBeNull()
- fireEvent.click(view.getByRole('button', { name: 'Copy link' }))
- await waitFor(() => expect(window.api.ui.writeClipboardText).toHaveBeenCalledWith(URL_TO_OPEN))
- fireEvent.click(system)
- await waitFor(() => expect(openUrl).toHaveBeenCalledExactlyOnceWith(URL_TO_OPEN))
- pointer(screen, 'mousedown', { ctrlKey: true })
- pointer(screen, 'mouseup', { ctrlKey: true })
- await waitFor(() => expect(openUrl).toHaveBeenCalledTimes(2))
- expect(foreground).not.toHaveBeenCalled()
- expect(toast.error).not.toHaveBeenCalled()
- const wrongPtyId = 'remote:hub-b@@handle-1'
- view.rerender(
-
- )
- await waitFor(() => expect(connect).toHaveBeenCalledTimes(2))
- await output(osc, wrongPtyId)
- const wrongScreen = screenFor(view.container)
- pointer(wrongScreen, 'mousedown', { ctrlKey: true })
- pointer(wrongScreen, 'mouseup', { ctrlKey: true })
- pointer(wrongScreen, 'contextmenu', { button: 2 })
- expect(document.querySelector('[data-link-action-popover]')).toBeNull()
- expect(openUrl).toHaveBeenCalledTimes(2)
- }
-)
-
it('gives one useful refusal when a real saved chooser action loses runtime browser eligibility', async () => {
const hostId = 'runtime:e'
const ptyId = 'remote:e@@handle-1'
@@ -398,126 +310,6 @@ it('gives one useful refusal when a real saved chooser action loses runtime brow
expect(input.mock.calls.map(([, data]) => data)).toEqual([])
})
-it('keeps None/middle/drag/nonlink reports and ordinary input live, refuses parser queries, and leaves native/paste context alone', async () => {
- store.setState((state) => ({
- settings: { ...state.settings!, terminalLinkClickBehavior: 'none' }
- }))
- const view = render()
- await waitFor(() => screenFor(view.container))
- await output(`\x1b[?1000h\x1b[?1006h${URL_TO_OPEN}`)
- const screen = screenFor(view.container)
- pointer(screen, 'mousedown')
- pointer(screen, 'mouseup')
- pointer(screen, 'mousedown', { button: 1, buttons: 4 })
- pointer(screen, 'mouseup', { button: 1 })
- await waitFor(() =>
- expect(input.mock.calls.some(([, data]) => data.startsWith('\x1b[<0;'))).toBe(true)
- )
- expect(input.mock.calls.map(([, data]) => data)).toEqual([
- '\x1b[<0;1;1M',
- '\x1b[<0;1;1m',
- '\x1b[<1;1;1M',
- '\x1b[<1;1;1m'
- ])
- expect(document.querySelector('[data-link-action-popover]')).toBeNull()
- expect(openUrl).not.toHaveBeenCalled()
- const prior = input.mock.calls.length
- await output('\x1b[6n')
- expect(input).toHaveBeenCalledTimes(prior)
- const textarea = view.container.querySelector('textarea')!
- fireEvent.keyDown(textarea, { key: 'x', code: 'KeyX', keyCode: 88 })
- fireEvent.input(textarea, { data: 'x', inputType: 'insertText' })
- await waitFor(() => expect(input).toHaveBeenCalledWith('pty-1', 'x'))
- const native = pointer(screen, 'contextmenu', { button: 2, ctrlKey: true })
- expect(native.defaultPrevented).toBe(false)
- store.setState((state) => ({ settings: { ...state.settings!, terminalRightClickToPaste: true } }))
- view.rerender()
- textarea.focus()
- pointer(screen, 'contextmenu', { button: 2 })
- await waitFor(() => expect(window.api.ui.readClipboardText).toHaveBeenCalled())
- expect(document.querySelector('[data-link-action-popover]')).toBeNull()
-})
-
-it.each([false, true])(
- 'preserves standalone normal/SSH defaults and sole-emulator query policy (answersQueries=%s)',
- async (answersQueries) => {
- const container = document.createElement('div')
- document.body.appendChild(container)
- const send = vi.fn(() => true)
- const instance = openStandaloneTerminal({
- container,
- options: { cols: 80, rows: 8, allowProposedApi: true },
- kittyKeyboardModes: new TerminalKittyKeyboardModeTracker({ kittyKeyboard: true }),
- sessionKey: 'plain-ssh:test',
- sendInput: send,
- answersQueries,
- getSettings: () => store.getState().settings,
- getMacOptionAsAlt: () => 'false',
- getTerminalInput: () => null
- })
- instances.push(instance)
- if (!instance) {
- throw new Error('Real constructor refused test layout')
- }
- const terminal = instance.terminal
- await new Promise((resolve) =>
- instance.write(`${osc}\r\n${URL_TO_OPEN}\x1b[6n`, { live: true, onDone: resolve })
- )
- expect(send.mock.calls.length > 0).toBe(answersQueries)
- terminal.input('ordinary')
- expect(send).toHaveBeenLastCalledWith('ordinary')
- const screen = screenFor(container)
- pointer(screen, 'mousemove', { buttons: 0 })
- await waitFor(() => expect(terminal.element?.getAttribute('title')).toBe(URL_TO_OPEN))
- pointer(screen, 'mousedown', { ctrlKey: true })
- pointer(screen, 'mouseup', { ctrlKey: true })
- await waitFor(() => expect(openUrl).toHaveBeenCalledWith(URL_TO_OPEN))
- expect(terminal.hasSelection()).toBe(false)
- expect(terminal.element?.getAttribute('title')).toBe(URL_TO_OPEN)
- pointer(screen, 'mouseleave')
- expect(terminal.element?.getAttribute('title')).toBeNull()
- // The same default callback is captured by the detected-URL provider, not only OSC.
- pointer(screen, 'mousemove', { clientY: 27 })
- pointer(screen, 'mousedown', { ctrlKey: true, clientY: 27 })
- pointer(screen, 'mouseup', { ctrlKey: true, clientY: 27 })
- await waitFor(() => expect(openUrl).toHaveBeenCalledTimes(2))
- expect(openUrl.mock.calls.map(([url]) => url)).toEqual([URL_TO_OPEN, URL_TO_OPEN])
- pointer(screen, 'mousedown', { clientY: 27 })
- pointer(screen, 'mouseup', { clientY: 27 })
- expect(openUrl).toHaveBeenCalledTimes(2)
- const injected = mountedInteraction()
- const injectedInteraction = injected.install()
- const raw = 'https:example.com'
- for (const current of [instance, injected.instance]) {
- const term = current.terminal
- const target = screenFor(term.element!.parentElement!)
- pointer(target, 'mouseleave')
- await new Promise((resolve) =>
- current.write(`\x1b[2J\x1b[H\x1b]8;;${raw}\x07Link\x1b]8;;\x07`, {
- live: true,
- onDone: resolve
- })
- )
- pointer(target, 'mousemove', { buttons: 0 })
- await waitFor(() => expect(term.element?.getAttribute('title')).toBe(raw))
- term.select(0, 0, 4)
- const clear = vi.spyOn(term, 'clearSelection')
- pointer(target, 'mousedown', { ctrlKey: true })
- pointer(target, 'mouseup', { ctrlKey: true })
- await waitFor(() => expect(openUrl).toHaveBeenLastCalledWith(raw))
- expect(clear).toHaveBeenCalled()
- expect(term.hasSelection()).toBe(false)
- clear.mockRestore()
- }
- expect(openUrl.mock.calls.map(([url]) => url)).toEqual([URL_TO_OPEN, URL_TO_OPEN, raw, raw])
- expect(injected.request).not.toHaveBeenCalled()
- expect(document.querySelector('[data-link-action-popover]')).toBeNull()
- injectedInteraction.dispose()
- instance.dispose()
- container.remove()
- }
-)
-
function mountedInteraction() {
return mountPreviewLinkInteraction(
source,
@@ -592,88 +384,6 @@ function cards(count: number): DashboardCard[] {
}))
}
-it('adds no provider or preview connection when the real board grows from 10 to 100 cards without an open preview', async () => {
- const provider = vi.spyOn(Terminal.prototype, 'registerLinkProvider')
- const view = render()
- view.rerender()
- expect(provider).not.toHaveBeenCalled()
- expect(window.api.terminalPreview.connect).not.toHaveBeenCalled()
- view.unmount()
- await verifyPopoutDefaultLinkPath({
- source,
- card: { ...cards(1)[0]!, ...source },
- provider,
- osc,
- readSettings: () => store.getState().settings,
- trackInstance: (instance) => instances.push(instance),
- pointer,
- screenFor,
- output,
- input,
- openUrl,
- subscribeToRouter: mocks.subscribe
- })
-})
-
-it('honors primary/alternate and Open on real literal URLs, keeps background context, and refuses unqualified/mismatched hosts before feedback', async () => {
- store.setState((state) => ({
- settings: { ...state.settings!, openLinksInApp: true, terminalLinkClickBehavior: 'open' }
- }))
- const foreground = vi.fn()
- const view = render(
-
- )
- await waitFor(() => screenFor(view.container))
- await output(URL_TO_OPEN)
- const screen = screenFor(view.container)
- // First literal click exercises the fallback when the provider has not finished hover discovery.
- pointer(screen, 'mousedown')
- pointer(screen, 'mouseup')
- await waitFor(() => expect(foreground).toHaveBeenCalledOnce())
- expect(document.querySelector('[data-link-action-popover]')).toBeNull()
- expect(openUrl).not.toHaveBeenCalled()
- pointer(screen, 'mousedown', { ctrlKey: true, shiftKey: true })
- pointer(screen, 'mouseup', { ctrlKey: true, shiftKey: true })
- await waitFor(() => expect(openUrl).toHaveBeenCalledExactlyOnceWith(URL_TO_OPEN))
- expect(foreground).toHaveBeenCalledOnce()
- store.setState((state) => ({
- settings: { ...state.settings!, openLinksInAppInBackground: true }
- }))
- view.rerender(
-
- )
- const observed = mocks.subscribe.mock.calls.length
- pointer(screen, 'mousedown', { ctrlKey: true })
- pointer(screen, 'mouseup', { ctrlKey: true })
- await waitFor(() => expect(mocks.subscribe.mock.results[observed]?.value).toHaveBeenCalledOnce())
- expect(foreground).toHaveBeenCalledOnce()
- view.rerender(
-
- )
- pointer(screen, 'mousedown')
- pointer(screen, 'mouseup')
- expect(document.querySelector('[data-link-action-popover]')).toBeNull()
- expect(openUrl).toHaveBeenCalledTimes(1)
- const remotePty = 'ssh:other@@pty-1'
- view.rerender(
-
- )
- await waitFor(() => expect(window.api.terminalPreview.connect).toHaveBeenCalledTimes(2))
- await output(URL_TO_OPEN, remotePty)
- pointer(screenFor(view.container), 'contextmenu', { button: 2 })
- // This real-shaped remote card has no eligible managed-browser route in the local-only workspace.
- await waitFor(() => expect(view.getByRole('button', { name: /System Browser/ })).toBeTruthy())
- expect(view.queryByRole('button', { name: /Orca Browser/ })).toBeNull()
-})
-
it('refuses real selected/drag/nonlink reports and retains the real in-window Board chooser and Settings handoff', async () => {
const preview = mountedInteraction()
const interaction = preview.install()
@@ -728,65 +438,3 @@ it('refuses real selected/drag/nonlink reports and retains the real in-window Bo
expect(store.getState().activeView).toBe('settings')
await waitFor(() => expect(document.querySelector('.xterm')).toBeNull())
})
-
-it('hands Settings through the actual in-window frame and shared popover without leaving the covering panel open', async () => {
- const close = vi.fn()
- const handoff = vi.fn()
- const card = {
- ...cards(1)[0]!,
- ...source,
- paneKey: 'pane-1',
- leafId: 'leaf-1',
- worktreeName: 'Workspace'
- }
- const view = render(
-
- )
- await waitFor(() => screenFor(view.container))
- await output(osc)
- const screen = screenFor(view.container)
- pointer(screen, 'mousedown')
- pointer(screen, 'mouseup')
- await waitFor(() =>
- expect(view.getByRole('button', { name: 'Terminal link settings' })).toBeTruthy()
- )
- fireEvent.click(view.getByRole('button', { name: 'Terminal link settings' }))
- expect(close).toHaveBeenCalledExactlyOnceWith(false)
- expect(handoff).toHaveBeenCalledOnce()
- expect(store.getState().activeView).toBe('settings')
-})
-
-it.each(['local', 'unknown'] as const)(
- 'keeps the common pane route and real Dashboard route destination/refusal equivalent for source=%s',
- async (owner) => {
- store.setState((state) => ({ settings: { ...state.settings!, openLinksInApp: false } }))
- handleTerminalHttpLink(URL_TO_OPEN, new MouseEvent('mouseup', { button: 0, ctrlKey: true }), {
- worktreeId: WORKSPACE,
- sourceTabId: 'source',
- sourceOwner: owner === 'local' ? { kind: 'local' } : { kind: 'unknown' },
- actionDestinations: { primary: 'system' }
- })
- const expected = owner === 'local' ? [URL_TO_OPEN] : []
- expect(openUrl.mock.calls.map(([url]) => url)).toEqual(expected)
- openUrl.mockClear()
- const view = render(
-
- )
- await waitFor(() => screenFor(view.container))
- await output(osc)
- const screen = screenFor(view.container)
- pointer(screen, 'mousedown', { ctrlKey: true })
- pointer(screen, 'mouseup', { ctrlKey: true })
- expect(openUrl.mock.calls.map(([url]) => url)).toEqual(expected)
- expect(document.querySelector('[data-link-action-popover]')).toBeNull()
- }
-)
diff --git a/src/renderer/src/components/dashboard-popout/dashboard-preview-popout-default-test-fixture.tsx b/src/renderer/src/components/dashboard-popout/dashboard-preview-popout-default-test-fixture.tsx
deleted file mode 100644
index b32fa4ee52a..00000000000
--- a/src/renderer/src/components/dashboard-popout/dashboard-preview-popout-default-test-fixture.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-import { act, fireEvent, render as renderWithoutApp, waitFor } from '@testing-library/react'
-import { expect, vi, type Mock, type MockInstance } from 'vitest'
-import type { Terminal } from '@xterm/xterm'
-import { toast } from 'sonner'
-import { URL_TO_OPEN } from '@/lib/browser-link-open.test-fixture'
-import type { GlobalSettings } from '../../../../shared/global-settings-types'
-import type { DashboardCard, DashboardSnapshot } from '../../../../shared/dashboard-snapshot'
-import * as standalone from '../standalone-terminal/open-standalone-terminal'
-import type { DashboardPreviewLinkSource } from './dashboard-preview-http-actions'
-import {
- mountPreviewLinkInteraction,
- observePreviewListeners
-} from './dashboard-preview-dom-test-fixture'
-import { DashboardPopoutRoot } from './DashboardPopoutRoot'
-
-export async function verifyPopoutDefaultLinkPath({
- source,
- card,
- provider,
- osc,
- readSettings,
- trackInstance,
- pointer,
- screenFor,
- output,
- input,
- openUrl,
- subscribeToRouter
-}: {
- source: DashboardPreviewLinkSource
- card: DashboardCard
- provider: MockInstance
- osc: string
- readSettings: () => GlobalSettings | null
- trackInstance: (instance: standalone.StandaloneTerminal | null) => void
- pointer: (screen: HTMLElement, type: string, options?: MouseEventInit) => MouseEvent
- screenFor: (container: HTMLElement) => HTMLElement
- output: (data: string, ptyId?: string) => Promise
- input: Mock<(pty: string, data: string) => Promise>
- openUrl: Mock<(url: string) => Promise>
- subscribeToRouter: Mock
-}): Promise {
- const bridges = new Set