mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-23 10:55:31 -06:00
test(ui): cover terminal picker pointer paths
This commit is contained in:
@@ -709,6 +709,115 @@ describe("OpenClawTerminalPanel", () => {
|
||||
expect(panel.renderRoot.querySelector(".tp-session-menu")).toBeNull();
|
||||
});
|
||||
|
||||
it("keeps a trigger pointerdown inside the picker before toggling closed", async () => {
|
||||
createGhosttyTerminalMock.mockResolvedValue(createTerminalController());
|
||||
const client: TerminalGatewayClient = {
|
||||
forceReconnect: () => {},
|
||||
request: async <T>(method: string) =>
|
||||
(method === "terminal.open"
|
||||
? terminalOpenResult("current-1")
|
||||
: method === "terminal.list"
|
||||
? { sessions: [] }
|
||||
: {}) as T,
|
||||
addEventListener: () => () => {},
|
||||
};
|
||||
const panel = document.createElement(TERMINAL_PANEL_ELEMENT_NAME) as OpenClawTerminalPanel;
|
||||
panel.client = client;
|
||||
panel.available = true;
|
||||
document.body.append(panel);
|
||||
panel.toggle();
|
||||
await waitForFast(() => expect(panel.renderRoot.querySelector(".tp-actions")).not.toBeNull());
|
||||
|
||||
const trigger = panel.renderRoot.querySelector<HTMLButtonElement>(
|
||||
'[aria-label="Terminal sessions"]',
|
||||
)!;
|
||||
trigger.click();
|
||||
await waitForFast(() =>
|
||||
expect(panel.renderRoot.querySelector(".tp-session-menu")).not.toBeNull(),
|
||||
);
|
||||
trigger.dispatchEvent(new MouseEvent("pointerdown", { bubbles: true, composed: true }));
|
||||
expect(panel.renderRoot.querySelector(".tp-session-menu")).not.toBeNull();
|
||||
trigger.click();
|
||||
await panel.updateComplete;
|
||||
expect(panel.renderRoot.querySelector(".tp-session-menu")).toBeNull();
|
||||
});
|
||||
|
||||
it("keeps shadow-DOM pointer actions inside the terminal session picker", async () => {
|
||||
createGhosttyTerminalMock.mockResolvedValue(createTerminalController());
|
||||
const requests: Array<{ method: string; params: unknown }> = [];
|
||||
const client: TerminalGatewayClient = {
|
||||
forceReconnect: () => {},
|
||||
request: async <T>(method: string, params?: unknown) => {
|
||||
requests.push({ method, params });
|
||||
if (method === "terminal.open") {
|
||||
return terminalOpenResult("current-1") as T;
|
||||
}
|
||||
if (method === "terminal.list") {
|
||||
return {
|
||||
sessions: [
|
||||
{
|
||||
...terminalOpenResult("detached-1"),
|
||||
agentId: "detached-agent",
|
||||
attached: false,
|
||||
createdAtMs: 1,
|
||||
},
|
||||
],
|
||||
} as T;
|
||||
}
|
||||
if (method === "terminal.attach") {
|
||||
return {
|
||||
...terminalOpenResult("detached-1"),
|
||||
agentId: "detached-agent",
|
||||
buffer: "",
|
||||
seq: 0,
|
||||
} as T;
|
||||
}
|
||||
return {} as T;
|
||||
},
|
||||
addEventListener: () => () => {},
|
||||
};
|
||||
const panel = document.createElement(TERMINAL_PANEL_ELEMENT_NAME) as OpenClawTerminalPanel;
|
||||
panel.client = client;
|
||||
panel.available = true;
|
||||
document.body.append(panel);
|
||||
panel.toggle();
|
||||
await waitForFast(() => expect(panel.renderRoot.querySelector(".tp-actions")).not.toBeNull());
|
||||
|
||||
const trigger = panel.renderRoot.querySelector<HTMLButtonElement>(
|
||||
'[aria-label="Terminal sessions"]',
|
||||
)!;
|
||||
trigger.click();
|
||||
await waitForFast(() =>
|
||||
expect(panel.renderRoot.querySelector(".tp-session")?.textContent).toContain(
|
||||
"detached-agent",
|
||||
),
|
||||
);
|
||||
|
||||
const refresh = panel.renderRoot.querySelector<HTMLButtonElement>(".tp-session-refresh")!;
|
||||
refresh.dispatchEvent(new MouseEvent("pointerdown", { bubbles: true, composed: true }));
|
||||
expect(panel.renderRoot.querySelector(".tp-session-menu")).not.toBeNull();
|
||||
refresh.click();
|
||||
await waitForFast(() => {
|
||||
expect(requests.filter(({ method }) => method === "terminal.list")).toHaveLength(2);
|
||||
});
|
||||
await waitForFast(() =>
|
||||
expect(panel.renderRoot.querySelector(".tp-session")?.textContent).toContain(
|
||||
"detached-agent",
|
||||
),
|
||||
);
|
||||
|
||||
const attach = panel.renderRoot.querySelector<HTMLButtonElement>(".tp-session")!;
|
||||
attach.dispatchEvent(new MouseEvent("pointerdown", { bubbles: true, composed: true }));
|
||||
expect(panel.renderRoot.querySelector(".tp-session-menu")).not.toBeNull();
|
||||
attach.click();
|
||||
await waitForFast(() =>
|
||||
expect(requests).toContainEqual({
|
||||
method: "terminal.attach",
|
||||
params: { sessionId: "detached-1" },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("shows a picker attach failure after the listed session disappears", async () => {
|
||||
createGhosttyTerminalMock
|
||||
.mockResolvedValueOnce(createTerminalController())
|
||||
|
||||
@@ -268,7 +268,10 @@ export class OpenClawTerminalPanel extends OpenClawLitElement {
|
||||
return;
|
||||
}
|
||||
const picker = this.renderRoot.querySelector(".tp-session-picker");
|
||||
if (picker && !event.composedPath().includes(picker)) {
|
||||
// Document capture sees retargeted shadow-DOM events. The composed path
|
||||
// preserves the picker wrapper so its trigger and actions stay clickable.
|
||||
const path = event.composedPath();
|
||||
if (picker && !path.includes(picker)) {
|
||||
this.closeSessionPicker(false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user