mirror of
https://github.com/Tencent/BrowserSkill.git
synced 2026-09-10 13:01:23 +08:00
refactor(dsh-plugin): simplify browser commands
This commit is contained in:
+48
-22
@@ -1,17 +1,17 @@
|
||||
// @vitest-environment happy-dom
|
||||
// browser_screenshot keyed toolview: view-model derivation from frozen blocks,
|
||||
// browser_inspect keyed toolview: view-model derivation from frozen blocks,
|
||||
// image/path-only/running/error rendering, the registration key, and the
|
||||
// session-bound attachment loader.
|
||||
|
||||
import type { RunningToolCall, ToolResultNode } from "@deepseek-ai/dsh-client-runtime/client";
|
||||
import { cleanup, render, screen, waitFor } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { apply } from "../../src/client/index";
|
||||
import {
|
||||
ScreenshotToolView,
|
||||
type ScreenshotToolViewProps,
|
||||
BrowserInspectToolView,
|
||||
type BrowserInspectToolViewProps,
|
||||
viewModelOf,
|
||||
} from "../../src/client/ScreenshotToolView";
|
||||
} from "../../src/client/BrowserInspectToolView";
|
||||
import { apply } from "../../src/client/index";
|
||||
|
||||
const ATTACHMENT = {
|
||||
attachmentId: "sha256:abc123",
|
||||
@@ -25,7 +25,7 @@ const ATTACHMENT = {
|
||||
function runningBlock(argsRaw: string): RunningToolCall {
|
||||
return {
|
||||
callId: "c1",
|
||||
name: "browser_screenshot",
|
||||
name: "browser_inspect",
|
||||
argsRaw,
|
||||
turn: 1,
|
||||
step: 1,
|
||||
@@ -41,7 +41,7 @@ function settledBlock(argsRaw: string, content: unknown[], isError = false): Too
|
||||
seq: 1,
|
||||
time: 0,
|
||||
callId: "c1",
|
||||
call: { name: "browser_screenshot", argsRaw },
|
||||
call: { name: "browser_inspect", argsRaw },
|
||||
callTime: 0,
|
||||
content,
|
||||
isError,
|
||||
@@ -58,14 +58,14 @@ afterEach(cleanup);
|
||||
|
||||
describe("viewModelOf", () => {
|
||||
it("derives the running model from the call frame", () => {
|
||||
const model = viewModelOf(runningBlock('{"session":"s1"}'));
|
||||
const model = viewModelOf(runningBlock('{"action":"screenshot","session":"s1"}'));
|
||||
expect(model.state).toBe("running");
|
||||
expect(model.command).toBe("bsk screenshot --session s1");
|
||||
expect(model.image).toBeNull();
|
||||
});
|
||||
|
||||
it("marks settled results carrying an image block", () => {
|
||||
const block = settledBlock("{}", [
|
||||
const block = settledBlock('{"action":"screenshot"}', [
|
||||
{ type: "text", text: IMAGE_TEXT },
|
||||
{ type: "image", attachment: ATTACHMENT },
|
||||
]);
|
||||
@@ -77,30 +77,56 @@ describe("viewModelOf", () => {
|
||||
});
|
||||
|
||||
it("keeps the path-only form image-free", () => {
|
||||
const model = viewModelOf(settledBlock("{}", [{ type: "text", text: PATH_TEXT }]));
|
||||
const model = viewModelOf(
|
||||
settledBlock('{"action":"screenshot"}', [{ type: "text", text: PATH_TEXT }]),
|
||||
);
|
||||
expect(model.state).toBe("ok");
|
||||
expect(model.image).toBeNull();
|
||||
expect(model.summary).toBe(PATH_TEXT);
|
||||
});
|
||||
|
||||
it("marks error results", () => {
|
||||
const model = viewModelOf(settledBlock("{}", [{ type: "text", text: "Error: boom" }], true));
|
||||
const model = viewModelOf(
|
||||
settledBlock('{"action":"screenshot"}', [{ type: "text", text: "Error: boom" }], true),
|
||||
);
|
||||
expect(model.state).toBe("error");
|
||||
});
|
||||
|
||||
it("renders non-screenshot inspect actions as ordinary terminal calls", () => {
|
||||
const model = viewModelOf(
|
||||
settledBlock('{"action":"observe","session":"s1"}', [
|
||||
{ type: "text", text: "page observation" },
|
||||
]),
|
||||
);
|
||||
expect(model.title).toBe("Observe");
|
||||
expect(model.command).toBe("bsk observe --session s1");
|
||||
expect(model.image).toBeNull();
|
||||
});
|
||||
|
||||
it("preserves action-specific arguments in diagnostic command cards", () => {
|
||||
const model = viewModelOf(
|
||||
runningBlock(
|
||||
'{"action":"console","session":"s1","tabId":7,"since":4,"limit":20,"maxTextChars":500,"includeStack":true}',
|
||||
),
|
||||
);
|
||||
expect(model.command).toBe(
|
||||
"bsk console --session s1 --tab-id 7 --since 4 --limit 20 --max-text-chars 500 --include-stack",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ScreenshotToolView", () => {
|
||||
const baseProps = { callId: "c1", toolName: "browser_screenshot", openFile: () => {} };
|
||||
describe("BrowserInspectToolView", () => {
|
||||
const baseProps = { callId: "c1", toolName: "browser_inspect", openFile: () => {} };
|
||||
const renderView = (
|
||||
block: ScreenshotToolViewProps["block"],
|
||||
loadImage: ScreenshotToolViewProps["loadImage"],
|
||||
block: BrowserInspectToolViewProps["block"],
|
||||
loadImage: BrowserInspectToolViewProps["loadImage"],
|
||||
) => {
|
||||
const props = { ...baseProps, block, loadImage } as unknown as ScreenshotToolViewProps;
|
||||
return render(<ScreenshotToolView {...props} />);
|
||||
const props = { ...baseProps, block, loadImage } as unknown as BrowserInspectToolViewProps;
|
||||
return render(<BrowserInspectToolView {...props} />);
|
||||
};
|
||||
|
||||
it("renders the screenshot image through the loader", async () => {
|
||||
const block = settledBlock("{}", [
|
||||
const block = settledBlock('{"action":"screenshot"}', [
|
||||
{ type: "text", text: IMAGE_TEXT },
|
||||
{ type: "image", attachment: ATTACHMENT },
|
||||
]);
|
||||
@@ -115,7 +141,7 @@ describe("ScreenshotToolView", () => {
|
||||
});
|
||||
|
||||
it("renders the path-only form without touching the loader", async () => {
|
||||
const block = settledBlock("{}", [{ type: "text", text: PATH_TEXT }]);
|
||||
const block = settledBlock('{"action":"screenshot"}', [{ type: "text", text: PATH_TEXT }]);
|
||||
const loadImage = vi.fn(async () => "blob:unused");
|
||||
renderView(block, loadImage);
|
||||
screen.getByRole("button", { name: /screenshot/i }).click();
|
||||
@@ -125,14 +151,14 @@ describe("ScreenshotToolView", () => {
|
||||
|
||||
it("renders the running form without output", () => {
|
||||
const loadImage = vi.fn();
|
||||
renderView(runningBlock("{}"), loadImage);
|
||||
renderView(runningBlock('{"action":"screenshot"}'), loadImage);
|
||||
expect(screen.getByText("bsk screenshot --session (current)")).toBeTruthy();
|
||||
expect(loadImage).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("client plugin registration", () => {
|
||||
it("registers the browser_screenshot toolview and the shell observation overlay", () => {
|
||||
it("registers the browser_inspect toolview and the shell observation overlay", () => {
|
||||
const registrations: { name: string; key?: string; id?: string }[] = [];
|
||||
const sessions = { binding: () => undefined };
|
||||
const ctx = {
|
||||
@@ -150,7 +176,7 @@ describe("client plugin registration", () => {
|
||||
};
|
||||
apply(ctx as never);
|
||||
expect(registrations).toEqual([
|
||||
{ name: "tool.call.toolview", key: "browser_screenshot" },
|
||||
{ name: "tool.call.toolview", key: "browser_inspect" },
|
||||
{ name: "shell.overlay", id: "bsk-observation" },
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user