Files
orca/src/preload/browser-find-subscriptions.test.ts
T
5165cd1e19 fix(browser): scope Cmd/Ctrl+F find to the focused split (#11348) (#11351)
* fix(browser): scope Cmd/Ctrl+F find to the focused split (#11348)

The browser pane's renderer-path Find handler is a window-global
capture-phase keydown listener, but it armed on `isActive` (the active
tab within its own group) rather than on whether its split holds focus.
In a terminal+browser split, the browser was therefore `isActive` even
while the terminal held keyboard focus, so it swallowed Cmd/Ctrl+F and
opened find-in-page in the browser instead of find-in-terminal.

Thread a focused-split signal (`isFocused`) from BrowserPaneOverlayLayer
— derived from `activeGroupIdByWorktree` — down to the Find handler and
gate the listener on it. This mirrors how terminal leaves already gate
global shortcuts via `focusedGroupId` in TabGroupSplitLayout. Floating
browser panels omit the prop and fall back to `isActive`, preserving
their behavior. The IPC path (webview guest focused) is unchanged; it
only fires when the guest genuinely has focus.

Not platform-specific: the chord resolves through `keybindingMatchesAction`
(Mod -> metaKey on macOS, ctrlKey elsewhere), so the same path is fixed on
macOS, Linux, and Windows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(browser): preserve Find before split focus settles

* fix(browser): handle stale focused split IDs

* fix(browser): route guest Find to source page

* test(browser): wait for split address bar

* test(browser): focus split before Find routing

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-30 14:17:26 -07:00

60 lines
1.9 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import { createBrowserFindSubscriptions } from './browser-find-subscriptions'
const FIRST_SOURCE = {
browserPageId: 'page-1',
browserWorkspaceId: 'workspace-1'
}
const SAME_WORKSPACE_SOURCE = {
browserPageId: 'page-2',
browserWorkspaceId: FIRST_SOURCE.browserWorkspaceId
}
const SAME_PAGE_SOURCE = {
browserPageId: FIRST_SOURCE.browserPageId,
browserWorkspaceId: 'workspace-2'
}
describe('browser Find subscriptions', () => {
it('dispatches only to the exact browser page and workspace owner', () => {
const subscriptions = createBrowserFindSubscriptions()
const firstCallback = vi.fn()
const sameWorkspaceCallback = vi.fn()
const samePageCallback = vi.fn()
subscriptions.subscribe(FIRST_SOURCE, firstCallback)
subscriptions.subscribe(SAME_WORKSPACE_SOURCE, sameWorkspaceCallback)
subscriptions.subscribe(SAME_PAGE_SOURCE, samePageCallback)
subscriptions.dispatch(FIRST_SOURCE)
expect(firstCallback).toHaveBeenCalledOnce()
expect(sameWorkspaceCallback).not.toHaveBeenCalled()
expect(samePageCallback).not.toHaveBeenCalled()
})
it('rejects malformed and partial source identities', () => {
const subscriptions = createBrowserFindSubscriptions()
const callback = vi.fn()
subscriptions.subscribe(FIRST_SOURCE, callback)
subscriptions.dispatch(undefined)
subscriptions.dispatch({ browserPageId: FIRST_SOURCE.browserPageId })
subscriptions.dispatch({
browserPageId: FIRST_SOURCE.browserPageId,
browserWorkspaceId: ''
})
expect(callback).not.toHaveBeenCalled()
})
it('drops empty ownership entries when subscribers clean up', () => {
const subscriptions = createBrowserFindSubscriptions()
const callback = vi.fn()
const unsubscribe = subscriptions.subscribe(FIRST_SOURCE, callback)
unsubscribe()
subscriptions.dispatch(FIRST_SOURCE)
expect(callback).not.toHaveBeenCalled()
})
})