mirror of
https://github.com/Tencent/BrowserSkill.git
synced 2026-09-10 13:01:23 +08:00
165 lines
4.9 KiB
TypeScript
165 lines
4.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { appendRecordedPayload, observeRecordedNavigation } from "../recording/step-buffer";
|
|
|
|
describe("recording-step-buffer", () => {
|
|
it("stores semantic click without summary", () => {
|
|
const buffer = { steps: [], navigation: { pendingNavigation: false } };
|
|
appendRecordedPayload(buffer, {
|
|
op: "click",
|
|
target: { tag: "button", role: "button", name: "发布" },
|
|
expects_navigation: true,
|
|
});
|
|
expect(buffer.steps).toEqual([
|
|
{
|
|
op: "click",
|
|
captureTarget: { tag: "button", role: "button", name: "发布" },
|
|
},
|
|
]);
|
|
expect(buffer.navigation.pendingNavigation).toBe(true);
|
|
});
|
|
|
|
it("keeps the hovered element description as a capture fallback", () => {
|
|
const buffer = { steps: [], navigation: { pendingNavigation: false } };
|
|
appendRecordedPayload(
|
|
buffer,
|
|
{
|
|
op: "hover",
|
|
target: { tag: "button", role: "button", name: "新建" },
|
|
geometry: {
|
|
rect: { x: 900, y: 8, w: 60, h: 32 },
|
|
tag: "button",
|
|
},
|
|
},
|
|
{
|
|
geometry: {
|
|
rect: { x: 900, y: 8, w: 60, h: 32 },
|
|
tag: "button",
|
|
},
|
|
},
|
|
);
|
|
expect(buffer.steps).toEqual([
|
|
{
|
|
op: "hover",
|
|
captureTarget: { tag: "button", role: "button", name: "新建" },
|
|
targetHint: {
|
|
geometry: {
|
|
rect: { x: 900, y: 8, w: 60, h: 32 },
|
|
tag: "button",
|
|
},
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("annotates navigated_to on action-caused navigation instead of wait_for_navigation", () => {
|
|
const buffer = {
|
|
steps: [
|
|
{
|
|
op: "click" as const,
|
|
captureTarget: { tag: "button", role: "button", name: "发布" },
|
|
},
|
|
],
|
|
navigation: {
|
|
currentUrl: "https://example.com/a",
|
|
pendingNavigation: true,
|
|
pendingNavigationDeadline: Date.now() + 5_000,
|
|
},
|
|
};
|
|
observeRecordedNavigation(buffer, "https://example.com/b", true);
|
|
expect(buffer.steps).toEqual([
|
|
{
|
|
op: "click",
|
|
captureTarget: { tag: "button", role: "button", name: "发布" },
|
|
navigatedTo: "https://example.com/b",
|
|
},
|
|
]);
|
|
expect(JSON.stringify(buffer.steps)).not.toContain("wait_for_navigation");
|
|
});
|
|
|
|
it("annotates navigated_to onto a select that auto-submits a navigation", () => {
|
|
const buffer = {
|
|
steps: [
|
|
{
|
|
op: "select" as const,
|
|
captureTarget: { tag: "select", role: "combobox", name: "分类" },
|
|
values: ["tech"],
|
|
},
|
|
],
|
|
navigation: {
|
|
currentUrl: "https://example.com/list",
|
|
pendingNavigation: true,
|
|
pendingNavigationDeadline: Date.now() + 5_000,
|
|
},
|
|
};
|
|
observeRecordedNavigation(buffer, "https://example.com/list?cat=tech", true);
|
|
expect(buffer.steps).toEqual([
|
|
{
|
|
op: "select",
|
|
captureTarget: { tag: "select", role: "combobox", name: "分类" },
|
|
values: ["tech"],
|
|
navigatedTo: "https://example.com/list?cat=tech",
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("emits navigate for uncaused URL changes", () => {
|
|
const buffer = {
|
|
steps: [],
|
|
navigation: { currentUrl: "https://example.com/a", pendingNavigation: false },
|
|
};
|
|
const result = observeRecordedNavigation(buffer, "https://example.com/b", false);
|
|
expect(result).toEqual({ kind: "appended", index: 0 });
|
|
expect(buffer.steps[0]).toMatchObject({
|
|
op: "navigate",
|
|
url: "https://example.com/b",
|
|
});
|
|
});
|
|
|
|
it("asks the recorder to coalesce redirect hops instead of emitting each one", () => {
|
|
const buffer = {
|
|
steps: [],
|
|
navigation: {
|
|
currentUrl: "https://passport.example/login",
|
|
pendingNavigation: false,
|
|
},
|
|
};
|
|
const hop1 = observeRecordedNavigation(
|
|
buffer,
|
|
"https://passport.example/callback",
|
|
false,
|
|
"link",
|
|
["server_redirect"],
|
|
);
|
|
expect(hop1).toEqual({
|
|
kind: "coalesce_redirect",
|
|
url: "https://passport.example/callback",
|
|
});
|
|
expect(buffer.steps).toEqual([]);
|
|
|
|
const hop2 = observeRecordedNavigation(buffer, "https://app.example/dashboard", false, "link", [
|
|
"client_redirect",
|
|
]);
|
|
expect(hop2).toEqual({
|
|
kind: "coalesce_redirect",
|
|
url: "https://app.example/dashboard",
|
|
});
|
|
expect(buffer.steps).toEqual([]);
|
|
expect(buffer.navigation.currentUrl).toBe("https://app.example/dashboard");
|
|
});
|
|
|
|
it("does not reuse redirect metadata for a later content-observed URL change", () => {
|
|
const buffer = {
|
|
steps: [],
|
|
navigation: {
|
|
currentUrl: "https://example.com/redirect",
|
|
pendingNavigation: false,
|
|
},
|
|
};
|
|
|
|
const result = observeRecordedNavigation(buffer, "https://example.com/spa");
|
|
|
|
expect(result).toEqual({ kind: "appended", index: 0 });
|
|
expect(buffer.steps[0]).toMatchObject({ op: "navigate", url: "https://example.com/spa" });
|
|
});
|
|
});
|