diff options
| author | Luke Parker <[email protected]> | 2026-03-17 12:55:58 +1000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-03-17 12:55:58 +1000 |
| commit | e416e59ea69f7600acbdb593ba68ac0fb1ee2633 (patch) | |
| tree | f1594d949fc3ad0d37f871e3d1028fcc77674035 /packages/app/src | |
| parent | cb69501098c603ccd7d3e3dbe6655d401c1d815c (diff) | |
| download | opencode-e416e59ea69f7600acbdb593ba68ac0fb1ee2633.tar.gz opencode-e416e59ea69f7600acbdb593ba68ac0fb1ee2633.zip | |
test(app): deflake slash terminal toggle flow (#17881)
Diffstat (limited to 'packages/app/src')
| -rw-r--r-- | packages/app/src/components/prompt-input.tsx | 16 | ||||
| -rw-r--r-- | packages/app/src/pages/session/terminal-panel.tsx | 9 | ||||
| -rw-r--r-- | packages/app/src/testing/prompt.ts | 56 | ||||
| -rw-r--r-- | packages/app/src/testing/terminal.ts | 15 |
4 files changed, 95 insertions, 1 deletions
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index b2553e4c0..4fbc82a70 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -36,6 +36,7 @@ import { useLanguage } from "@/context/language" import { usePlatform } from "@/context/platform" import { useSessionLayout } from "@/pages/session/session-layout" import { createSessionTabs } from "@/pages/session/helpers" +import { promptEnabled, promptProbe } from "@/testing/prompt" import { createTextFragment, getCursorPosition, setCursorPosition, setRangeEdge } from "./prompt-input/editor-dom" import { createPromptAttachments } from "./prompt-input/attachments" import { ACCEPTED_FILE_TYPES } from "./prompt-input/files" @@ -604,6 +605,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { const handleSlashSelect = (cmd: SlashCommand | undefined) => { if (!cmd) return + promptProbe.select(cmd.id) closePopover() if (cmd.type === "custom") { @@ -692,6 +694,20 @@ export const PromptInput: Component<PromptInputProps> = (props) => { }) }) + if (promptEnabled()) { + createEffect(() => { + promptProbe.set({ + popover: store.popover, + slash: { + active: slashActive() ?? null, + ids: slashFlat().map((cmd) => cmd.id), + }, + }) + }) + + onCleanup(() => promptProbe.clear()) + } + const selectPopoverActive = () => { if (store.popover === "at") { const items = atFlat() diff --git a/packages/app/src/pages/session/terminal-panel.tsx b/packages/app/src/pages/session/terminal-panel.tsx index e78ebecfc..d62d91c19 100644 --- a/packages/app/src/pages/session/terminal-panel.tsx +++ b/packages/app/src/pages/session/terminal-panel.tsx @@ -18,8 +18,10 @@ import { terminalTabLabel } from "@/pages/session/terminal-label" import { createSizing, focusTerminalById } from "@/pages/session/helpers" import { getTerminalHandoff, setTerminalHandoff } from "@/pages/session/handoff" import { useSessionLayout } from "@/pages/session/session-layout" +import { terminalProbe } from "@/testing/terminal" export function TerminalPanel() { + const delays = [120, 240] const layout = useLayout() const terminal = useTerminal() const language = useLanguage() @@ -79,16 +81,20 @@ export function TerminalPanel() { ) const focus = (id: string) => { + const probe = terminalProbe(id) + probe.focus(delays.length + 1) focusTerminalById(id) const frame = requestAnimationFrame(() => { + probe.step() if (!opened()) return if (terminal.active() !== id) return focusTerminalById(id) }) - const timers = [120, 240].map((ms) => + const timers = delays.map((ms) => window.setTimeout(() => { + probe.step() if (!opened()) return if (terminal.active() !== id) return focusTerminalById(id) @@ -96,6 +102,7 @@ export function TerminalPanel() { ) return () => { + probe.focus(0) cancelAnimationFrame(frame) for (const timer of timers) clearTimeout(timer) } diff --git a/packages/app/src/testing/prompt.ts b/packages/app/src/testing/prompt.ts new file mode 100644 index 000000000..e11462f30 --- /dev/null +++ b/packages/app/src/testing/prompt.ts @@ -0,0 +1,56 @@ +import type { E2EWindow } from "./terminal" + +export type PromptProbeState = { + popover: "at" | "slash" | null + slash: { + active: string | null + ids: string[] + } + selected: string | null + selects: number +} + +export const promptEnabled = () => { + if (typeof window === "undefined") return false + return (window as E2EWindow).__opencode_e2e?.prompt?.enabled === true +} + +const root = () => { + if (!promptEnabled()) return + return (window as E2EWindow).__opencode_e2e?.prompt +} + +export const promptProbe = { + set(input: Omit<PromptProbeState, "selected" | "selects">) { + const state = root() + if (!state) return + state.current = { + popover: input.popover, + slash: { + active: input.slash.active, + ids: [...input.slash.ids], + }, + selected: state.current?.selected ?? null, + selects: state.current?.selects ?? 0, + } + }, + select(id: string) { + const state = root() + if (!state) return + const prev = state.current + state.current = { + popover: prev?.popover ?? null, + slash: { + active: prev?.slash.active ?? null, + ids: [...(prev?.slash.ids ?? [])], + }, + selected: id, + selects: (prev?.selects ?? 0) + 1, + } + }, + clear() { + const state = root() + if (!state) return + state.current = undefined + }, +} diff --git a/packages/app/src/testing/terminal.ts b/packages/app/src/testing/terminal.ts index af1c33309..2bca39b31 100644 --- a/packages/app/src/testing/terminal.ts +++ b/packages/app/src/testing/terminal.ts @@ -7,6 +7,7 @@ export type TerminalProbeState = { connects: number rendered: string settled: number + focusing: number } type TerminalProbeControl = { @@ -19,6 +20,10 @@ export type E2EWindow = Window & { enabled?: boolean current?: ModelProbeState } + prompt?: { + enabled?: boolean + current?: import("./prompt").PromptProbeState + } terminal?: { enabled?: boolean terminals?: Record<string, TerminalProbeState> @@ -32,6 +37,7 @@ const seed = (): TerminalProbeState => ({ connects: 0, rendered: "", settled: 0, + focusing: 0, }) const root = () => { @@ -88,6 +94,15 @@ export const terminalProbe = (id: string) => { const prev = state[id] ?? seed() state[id] = { ...prev, settled: prev.settled + 1 } }, + focus(count: number) { + set({ focusing: Math.max(0, count) }) + }, + step() { + const state = terms() + if (!state) return + const prev = state[id] ?? seed() + state[id] = { ...prev, focusing: Math.max(0, prev.focusing - 1) } + }, control(next: Partial<TerminalProbeControl>) { const state = controls() if (!state) return |
