fix: improve browser upload triggering

This commit is contained in:
Peter Steinberger
2026-01-01 09:35:20 +00:00
parent fbcbc60e85
commit bf0bee58b3
9 changed files with 50 additions and 0 deletions

View File

@@ -93,6 +93,7 @@ export async function browserArmFileChooser(
baseUrl: string,
opts: {
paths: string[];
ref?: string;
targetId?: string;
timeoutMs?: number;
},
@@ -104,6 +105,7 @@ export async function browserArmFileChooser(
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
paths: opts.paths,
ref: opts.ref,
targetId: opts.targetId,
timeoutMs: opts.timeoutMs,
}),

View File

@@ -283,6 +283,20 @@ export async function armFileUploadViaPlaywright(opts: {
return;
}
await fileChooser.setFiles(opts.paths);
try {
const input =
typeof fileChooser.element === "function"
? await fileChooser.element()
: null;
if (input) {
await input.evaluate((el) => {
el.dispatchEvent(new Event("input", { bubbles: true }));
el.dispatchEvent(new Event("change", { bubbles: true }));
});
}
} catch {
// Best-effort for sites that don't react to setFiles alone.
}
})
.catch(() => {
// Ignore timeouts; the chooser may never appear.

View File

@@ -338,6 +338,7 @@ export function registerBrowserAgentRoutes(
app.post("/hooks/file-chooser", async (req, res) => {
const body = readBody(req);
const targetId = toStringOrEmpty(body.targetId) || undefined;
const ref = toStringOrEmpty(body.ref) || undefined;
const paths = toStringArray(body.paths) ?? [];
const timeoutMs = toNumber(body.timeoutMs);
if (!paths.length) return jsonError(res, 400, "paths are required");
@@ -351,6 +352,13 @@ export function registerBrowserAgentRoutes(
paths,
timeoutMs: timeoutMs ?? undefined,
});
if (ref) {
await pw.clickViaPlaywright({
cdpPort: ctx.state().cdpPort,
targetId: tab.targetId,
ref,
});
}
res.json({ ok: true });
} catch (err) {
handleRouteError(ctx, res, err);

View File

@@ -475,6 +475,24 @@ describe("browser control server", () => {
timeoutMs: 1234,
});
const uploadWithRef = await realFetch(`${base}/hooks/file-chooser`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ paths: ["/tmp/b.txt"], ref: "e12" }),
}).then((r) => r.json());
expect(uploadWithRef).toMatchObject({ ok: true });
expect(pwMocks.armFileUploadViaPlaywright).toHaveBeenCalledWith({
cdpPort: testPort + 1,
targetId: "abcd1234",
paths: ["/tmp/b.txt"],
timeoutMs: undefined,
});
expect(pwMocks.clickViaPlaywright).toHaveBeenCalledWith({
cdpPort: testPort + 1,
targetId: "abcd1234",
ref: "e12",
});
const dialog = await realFetch(`${base}/hooks/dialog`, {
method: "POST",
headers: { "Content-Type": "application/json" },