Fix status bar runtime target render loop (#18685)

This commit is contained in:
Jinwoo Hong
2026-09-04 15:09:15 -04:00
committed by GitHub
parent 3e4fd4a7af
commit 5412276776
2 changed files with 92 additions and 3 deletions
@@ -0,0 +1,89 @@
// @vitest-environment happy-dom
import React, { act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
vi.mock('@/components/ui/popover', () => ({
Popover: ({ children }: { children: React.ReactNode }) => <>{children}</>,
PopoverContent: ({ children }: { children: React.ReactNode }) => <>{children}</>,
PopoverTrigger: ({ children }: { children: React.ReactNode }) => <>{children}</>
}))
vi.mock('@/components/ui/tooltip', () => ({
Tooltip: ({ children }: { children: React.ReactNode }) => <>{children}</>,
TooltipContent: ({ children }: { children: React.ReactNode }) => <>{children}</>,
TooltipTrigger: ({ children }: { children: React.ReactNode }) => <>{children}</>
}))
vi.mock('@/components/SelectedTextCopyMenu', () => ({
SelectedTextCopyMenu: ({ children }: { children: React.ReactNode }) => <>{children}</>
}))
vi.mock('./ports-status-popover-rows', () => ({
PortRow: () => <div />,
WorkspaceGroupRows: () => <div />
}))
vi.mock('@/lib/react-error-boundary-reporting', () => ({
reportReactErrorBoundaryCrash: vi.fn()
}))
vi.mock('@/i18n/i18n', () => ({
translate: (_key: string, fallback: string, options?: Record<string, unknown>) =>
options
? fallback.replace(/{{(\w+)}}/g, (_match, name: string) => String(options[name] ?? ''))
: fallback
}))
import { RecoverableRenderErrorBoundary } from '../error-boundaries/RecoverableRenderErrorBoundary'
import { useAppStore } from '@/store'
import { PortsStatusSegment } from './PortsStatusSegment'
describe('PortsStatusSegment render stability', () => {
let container: HTMLDivElement
let root: Root
let consoleError: ReturnType<typeof vi.spyOn>
beforeEach(() => {
useAppStore.setState(useAppStore.getInitialState(), true)
container = document.createElement('div')
document.body.appendChild(container)
root = createRoot(container)
consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined)
})
afterEach(() => {
act(() => root.unmount())
container.remove()
consoleError.mockRestore()
})
it('keeps the status controls mounted when the runtime owner is local', () => {
act(() => {
root.render(
<RecoverableRenderErrorBoundary
boundaryId="oracle.status-bar"
surface="overlay"
compact
reportAsCrash={false}
title="The status bar hit an error."
description="Retry the status bar to remount its controls."
>
<PortsStatusSegment iconOnly={false} />
</RecoverableRenderErrorBoundary>
)
})
const underlyingException = consoleError.mock.calls.find(
([message, error]) =>
message === '[oracle.status-bar] render crash contained by boundary' &&
error instanceof Error &&
error.message.includes('Maximum update depth exceeded')
)
expect.soft(container.textContent).not.toContain('The status bar hit an error.')
expect.soft(underlyingException).toBeUndefined()
expect(container.querySelector('button[aria-label^="Ports, 0 workspace"]')).not.toBeNull()
})
})
@@ -1,3 +1,4 @@
import { useMemo } from 'react'
import { useAppStore } from '@/store'
import { getExecutionHostIdForWorktree } from '@/lib/worktree-runtime-owner'
import { runtimeTargetForExecutionHostId, type RuntimeClientTarget } from './runtime-client-target'
@@ -10,7 +11,6 @@ import { runtimeTargetForExecutionHostId, type RuntimeClientTarget } from './run
export function useWorktreeRuntimeTarget(
worktreeId: string | null | undefined
): RuntimeClientTarget | null {
return useAppStore((state) =>
runtimeTargetForExecutionHostId(getExecutionHostIdForWorktree(state, worktreeId))
)
const executionHostId = useAppStore((state) => getExecutionHostIdForWorktree(state, worktreeId))
return useMemo(() => runtimeTargetForExecutionHostId(executionHostId), [executionHostId])
}