mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 04:32:44 +00:00
feat(browser): add ai snapshot refs + click
This commit is contained in:
143
src/browser/pw-ai.test.ts
Normal file
143
src/browser/pw-ai.test.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("playwright-core", () => ({
|
||||
chromium: {
|
||||
connectOverCDP: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
type FakeSession = {
|
||||
send: ReturnType<typeof vi.fn>;
|
||||
detach: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
|
||||
function createPage(opts: {
|
||||
targetId: string;
|
||||
snapshotFull?: string;
|
||||
hasSnapshotForAI?: boolean;
|
||||
}) {
|
||||
const session: FakeSession = {
|
||||
send: vi.fn().mockResolvedValue({
|
||||
targetInfo: { targetId: opts.targetId },
|
||||
}),
|
||||
detach: vi.fn().mockResolvedValue(undefined),
|
||||
};
|
||||
|
||||
const context = {
|
||||
newCDPSession: vi.fn().mockResolvedValue(session),
|
||||
};
|
||||
|
||||
const click = vi.fn().mockResolvedValue(undefined);
|
||||
const locator = vi.fn().mockReturnValue({ click });
|
||||
|
||||
const page = {
|
||||
context: () => context,
|
||||
locator,
|
||||
...(opts.hasSnapshotForAI === false
|
||||
? {}
|
||||
: {
|
||||
_snapshotForAI: vi
|
||||
.fn()
|
||||
.mockResolvedValue({ full: opts.snapshotFull ?? "SNAP" }),
|
||||
}),
|
||||
};
|
||||
|
||||
return { page, session, locator, click };
|
||||
}
|
||||
|
||||
function createBrowser(pages: unknown[]) {
|
||||
const ctx = {
|
||||
pages: () => pages,
|
||||
};
|
||||
return {
|
||||
contexts: () => [ctx],
|
||||
on: vi.fn(),
|
||||
close: vi.fn().mockResolvedValue(undefined),
|
||||
};
|
||||
}
|
||||
|
||||
async function importModule() {
|
||||
return await import("./pw-ai.js");
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
const mod = await importModule();
|
||||
await mod.closePlaywrightBrowserConnection();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("pw-ai", () => {
|
||||
it("captures an ai snapshot via Playwright for a specific target", async () => {
|
||||
const { chromium } = await import("playwright-core");
|
||||
const p1 = createPage({ targetId: "T1", snapshotFull: "ONE" });
|
||||
const p2 = createPage({ targetId: "T2", snapshotFull: "TWO" });
|
||||
const browser = createBrowser([p1.page, p2.page]);
|
||||
|
||||
(
|
||||
chromium.connectOverCDP as unknown as ReturnType<typeof vi.fn>
|
||||
).mockResolvedValue(browser);
|
||||
|
||||
const mod = await importModule();
|
||||
const res = await mod.snapshotAiViaPlaywright({
|
||||
cdpPort: 18792,
|
||||
targetId: "T2",
|
||||
});
|
||||
|
||||
expect(res.snapshot).toBe("TWO");
|
||||
expect(p1.session.detach).toHaveBeenCalledTimes(1);
|
||||
expect(p2.session.detach).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("clicks a ref using aria-ref locator", async () => {
|
||||
const { chromium } = await import("playwright-core");
|
||||
const p1 = createPage({ targetId: "T1" });
|
||||
const browser = createBrowser([p1.page]);
|
||||
(
|
||||
chromium.connectOverCDP as unknown as ReturnType<typeof vi.fn>
|
||||
).mockResolvedValue(browser);
|
||||
|
||||
const mod = await importModule();
|
||||
await mod.clickRefViaPlaywright({
|
||||
cdpPort: 18792,
|
||||
targetId: "T1",
|
||||
ref: "76",
|
||||
});
|
||||
|
||||
expect(p1.locator).toHaveBeenCalledWith("aria-ref=76");
|
||||
expect(p1.click).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("fails with a clear error when _snapshotForAI is missing", async () => {
|
||||
const { chromium } = await import("playwright-core");
|
||||
const p1 = createPage({ targetId: "T1", hasSnapshotForAI: false });
|
||||
const browser = createBrowser([p1.page]);
|
||||
(
|
||||
chromium.connectOverCDP as unknown as ReturnType<typeof vi.fn>
|
||||
).mockResolvedValue(browser);
|
||||
|
||||
const mod = await importModule();
|
||||
await expect(
|
||||
mod.snapshotAiViaPlaywright({ cdpPort: 18792, targetId: "T1" }),
|
||||
).rejects.toThrow(/_snapshotForAI/i);
|
||||
});
|
||||
|
||||
it("reuses the CDP connection for repeated calls", async () => {
|
||||
const { chromium } = await import("playwright-core");
|
||||
const p1 = createPage({ targetId: "T1", snapshotFull: "ONE" });
|
||||
const browser = createBrowser([p1.page]);
|
||||
const connect = chromium.connectOverCDP as unknown as ReturnType<
|
||||
typeof vi.fn
|
||||
>;
|
||||
connect.mockResolvedValue(browser);
|
||||
|
||||
const mod = await importModule();
|
||||
await mod.snapshotAiViaPlaywright({ cdpPort: 18792, targetId: "T1" });
|
||||
await mod.clickRefViaPlaywright({
|
||||
cdpPort: 18792,
|
||||
targetId: "T1",
|
||||
ref: "1",
|
||||
});
|
||||
|
||||
expect(connect).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user