From a1961e689f615eed05d7f59efeed5106063cd9de Mon Sep 17 00:00:00 2001 From: Arul Sharma <31745423+arul28@users.noreply.github.com> Date: Mon, 29 Jun 2026 17:39:25 -0400 Subject: [PATCH] Fix iOS simulator inspect hover after attach --- .../chat/ChatIosSimulatorPanel.test.tsx | 90 +++++++++++++++++++ .../components/chat/ChatIosSimulatorPanel.tsx | 2 +- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/renderer/components/chat/ChatIosSimulatorPanel.test.tsx b/apps/desktop/src/renderer/components/chat/ChatIosSimulatorPanel.test.tsx index dcd243fdc..00710c493 100644 --- a/apps/desktop/src/renderer/components/chat/ChatIosSimulatorPanel.test.tsx +++ b/apps/desktop/src/renderer/components/chat/ChatIosSimulatorPanel.test.tsx @@ -837,6 +837,96 @@ describe("ChatIosSimulatorPanel", () => { expect(api.renderPreview).not.toHaveBeenCalled(); }); + it("keeps the inspect hover target live after attaching simulator context", async () => { + vi.stubGlobal("PointerEvent", MouseEvent); + vi.stubGlobal("Image", class { + onload: (() => void) | null = null; + onerror: (() => void) | null = null; + set src(_value: string) { + queueMicrotask(() => this.onerror?.()); + } + }); + const settingsElement: IosScreenElement = { + ...inspectElement, + id: "element-2", + label: "Settings", + identifier: "settingsButton", + componentId: "SettingsView/SettingsButton", + sourceFile: "SettingsView.swift", + sourceLine: 24, + frame: { x: 190, y: 190, width: 60, height: 40 }, + pixelFrame: { x: 570, y: 570, width: 180, height: 120 }, + }; + const onAddContext = vi.fn(); + const { api } = installIosSimulatorApi({ + screenElements: [inspectElement, settingsElement], + previewTargets: [previewTarget], + }); + api.selectPoint.mockImplementation(async (args: { x: number; y: number }) => { + const element = args.x >= settingsElement.pixelFrame.x + ? settingsElement + : inspectElement; + return { + item: { + kind: "ios_simulator_target", + id: `ios:${element.id}`, + deviceUdid: device.udid, + label: element.label, + source: element.source, + screenshotDataUrl: null, + metadata: {}, + }, + source: element.source, + }; + }); + + render( + , + ); + + await waitFor(() => expect(document.querySelector("video")).toBeTruthy()); + fireEvent.click(screen.getByRole("button", { name: "Inspect" })); + const image = await screen.findByAltText("iOS Simulator snapshot") as HTMLImageElement; + const imageRect = { + x: 0, + y: 0, + left: 0, + top: 0, + right: 393, + bottom: 852, + width: 393, + height: 852, + toJSON: () => ({}), + } as DOMRect; + image.getBoundingClientRect = () => imageRect; + if (image.parentElement) { + image.parentElement.getBoundingClientRect = () => imageRect; + } + + fireEvent.pointerDown(image, { clientX: 50, clientY: 40 }); + await screen.findByText(/Added selected UI context/); + expect(onAddContext).toHaveBeenCalledWith(expect.objectContaining({ label: "Continue" })); + + fireEvent.pointerMove(image, { clientX: 210, clientY: 210 }); + expect(await screen.findByText("Settings")).toBeTruthy(); + + fireEvent.pointerDown(image, { clientX: 210, clientY: 210 }); + + await waitFor(() => { + expect(api.selectPoint).toHaveBeenLastCalledWith({ + deviceUdid: device.udid, + projectRoot: "/tmp/project", + x: 660, + y: 630, + }); + expect(onAddContext).toHaveBeenLastCalledWith(expect.objectContaining({ label: "Settings" })); + }); + }); + it("treats Swift #fileID source paths as the same Preview Lab match", async () => { vi.stubGlobal("PointerEvent", MouseEvent); vi.stubGlobal("Image", class { diff --git a/apps/desktop/src/renderer/components/chat/ChatIosSimulatorPanel.tsx b/apps/desktop/src/renderer/components/chat/ChatIosSimulatorPanel.tsx index 2e6b8e01e..62e79d0b3 100644 --- a/apps/desktop/src/renderer/components/chat/ChatIosSimulatorPanel.tsx +++ b/apps/desktop/src/renderer/components/chat/ChatIosSimulatorPanel.tsx @@ -2354,7 +2354,7 @@ export function ChatIosSimulatorPanel({ ? `Snapshot ready with ${snapshotElementCount} selectable item${snapshotElementCount === 1 ? "" : "s"}.` : "Snapshot ready with no selectable elements. Click a point or use Screenshot to attach visual context." : null; - const activeInspectElement = selectedElement ?? hoveredElement; + const activeInspectElement = hoveredElement ?? selectedElement; const activeInspectSource = activeInspectElement?.source ?? null; let previewModeHint: string | null = null; if (mode === "preview") {