mirror of
https://github.com/Tencent/BrowserSkill.git
synced 2026-09-10 13:01:23 +08:00
feat(bsk): fix different type of upload
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { SessionManager } from "@/session-manager/manager";
|
||||
import { type DownloadsApi, handleDownload } from "../download";
|
||||
import { uploadThroughFileChooser } from "../file-chooser";
|
||||
import type { CdpRunner } from "../shared";
|
||||
import { handleUpload } from "../upload";
|
||||
|
||||
@@ -37,7 +38,7 @@ function fakeEvent<T extends (...args: never[]) => void>() {
|
||||
}
|
||||
|
||||
describe("file transfer tools", () => {
|
||||
it("arms chooser interception before clicking and injects only staged paths", async () => {
|
||||
it("enables chooser observation before clicking and injects only staged paths", async () => {
|
||||
const manager = sessions();
|
||||
const ctx = await manager.start("s1");
|
||||
ctx.refStore.set("e3", 123, { tabId: 4 });
|
||||
@@ -82,13 +83,135 @@ describe("file transfer tools", () => {
|
||||
|
||||
expect(result).toMatchObject({ tab_id: 4, file_names: ["one.png", "two.png"] });
|
||||
expect(calls[0]).toMatchObject({
|
||||
method: "Page.setInterceptFileChooserDialog",
|
||||
params: { enabled: true },
|
||||
method: "Page.enable",
|
||||
params: { enableFileChooserOpenedEvent: true },
|
||||
});
|
||||
expect(calls).toContainEqual({
|
||||
method: "DOM.setFileInputFiles",
|
||||
params: { files: ["/private/stage/one", "/private/stage/two"], backendNodeId: 456 },
|
||||
});
|
||||
expect(calls.at(-1)).toEqual({
|
||||
method: "Page.enable",
|
||||
params: { enableFileChooserOpenedEvent: false },
|
||||
});
|
||||
});
|
||||
|
||||
it("reports File System Access pickers as an explicit manual fallback", async () => {
|
||||
let eventHandler: Parameters<NonNullable<CdpRunner["onEvent"]>>[0] | undefined;
|
||||
const cdp: CdpRunner = {
|
||||
onEvent: (handler) => {
|
||||
eventHandler = handler;
|
||||
return { dispose: vi.fn() };
|
||||
},
|
||||
send: vi.fn(async () => ({})) as unknown as CdpRunner["send"],
|
||||
};
|
||||
|
||||
const result = await uploadThroughFileChooser({
|
||||
cdp,
|
||||
target: { tabId: 4 },
|
||||
files: ["/private/stage/one"],
|
||||
timeoutMs: 100,
|
||||
trigger: async () => {
|
||||
eventHandler?.({ tabId: 4 }, "Page.fileChooserOpened", { mode: "selectSingle" });
|
||||
return { tab_id: 4, x: 10, y: 10 };
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
code: "unsupported",
|
||||
message: "this file chooser is not backed by an input element",
|
||||
data: {
|
||||
reason: "unsupported_file_chooser",
|
||||
chooser_kind: "non_input",
|
||||
manual_fallback_available: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("bounds a stuck chooser-control command and resets uncertain CDP state", async () => {
|
||||
const detach = vi.fn(async () => {});
|
||||
const cdp: CdpRunner = {
|
||||
onEvent: () => ({ dispose: vi.fn() }),
|
||||
send: vi.fn(() => new Promise<never>(() => {})) as unknown as CdpRunner["send"],
|
||||
detach,
|
||||
};
|
||||
|
||||
const result = await uploadThroughFileChooser({
|
||||
cdp,
|
||||
target: { tabId: 4 },
|
||||
files: ["/private/stage/one"],
|
||||
timeoutMs: 5,
|
||||
trigger: vi.fn(),
|
||||
});
|
||||
|
||||
expect(result).toMatchObject({
|
||||
code: "timeout",
|
||||
data: { reason: "file_chooser_control_failed", phase: "enable_events" },
|
||||
});
|
||||
expect(detach).toHaveBeenCalledWith(4);
|
||||
});
|
||||
|
||||
it("distinguishes a completed click that did not open a chooser", async () => {
|
||||
const send = vi.fn(async () => ({})) as unknown as CdpRunner["send"];
|
||||
const cdp: CdpRunner = {
|
||||
onEvent: () => ({ dispose: vi.fn() }),
|
||||
send,
|
||||
};
|
||||
|
||||
const result = await uploadThroughFileChooser({
|
||||
cdp,
|
||||
target: { tabId: 4 },
|
||||
files: ["/private/stage/one"],
|
||||
timeoutMs: 5,
|
||||
trigger: async () => ({ tab_id: 4, x: 10, y: 10 }),
|
||||
});
|
||||
|
||||
expect(result).toMatchObject({
|
||||
code: "timeout",
|
||||
data: { reason: "file_chooser_not_opened", phase: "await_event" },
|
||||
});
|
||||
expect(send).toHaveBeenLastCalledWith(4, "Page.enable", {
|
||||
enableFileChooserOpenedEvent: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("accepts chooser events only from the exact CDP target", async () => {
|
||||
let eventHandler: Parameters<NonNullable<CdpRunner["onEvent"]>>[0] | undefined;
|
||||
const setFiles = vi.fn();
|
||||
const cdp: CdpRunner = {
|
||||
onEvent: (handler) => {
|
||||
eventHandler = handler;
|
||||
return { dispose: vi.fn() };
|
||||
},
|
||||
send: vi.fn(async () => ({})) as unknown as CdpRunner["send"],
|
||||
sendToTarget: vi.fn(async (_target, method, params) => {
|
||||
if (method === "DOM.setFileInputFiles") setFiles(params);
|
||||
return {};
|
||||
}) as unknown as NonNullable<CdpRunner["sendToTarget"]>,
|
||||
};
|
||||
|
||||
const result = await uploadThroughFileChooser({
|
||||
cdp,
|
||||
target: { tabId: 4, sessionId: "child-a" },
|
||||
files: ["/private/stage/one"],
|
||||
timeoutMs: 100,
|
||||
trigger: async () => {
|
||||
eventHandler?.({ tabId: 4, sessionId: "child-b" }, "Page.fileChooserOpened", {
|
||||
backendNodeId: 111,
|
||||
});
|
||||
eventHandler?.({ tabId: 4, sessionId: "child-a" }, "Page.fileChooserOpened", {
|
||||
backendNodeId: 222,
|
||||
});
|
||||
return { tab_id: 4, x: 10, y: 10 };
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toMatchObject({ click: { tab_id: 4 } });
|
||||
expect(setFiles).toHaveBeenCalledOnce();
|
||||
expect(setFiles).toHaveBeenCalledWith({
|
||||
files: ["/private/stage/one"],
|
||||
backendNodeId: 222,
|
||||
});
|
||||
});
|
||||
|
||||
it("captures the one download created under daemon staging", async () => {
|
||||
|
||||
Reference in New Issue
Block a user