fix: 修复网页输入聚焦与降级写入

This commit is contained in:
yu 2026-10-28 11:27:26 +08:00
parent bec3d9daa4
commit ced89e26cf

View File

@ -391,7 +391,17 @@ export class BrowserSession implements BrowserLike {
async type(selector: unknown, text: string, clearFirst = true, timeoutMs?: number): Promise<unknown> { async type(selector: unknown, text: string, clearFirst = true, timeoutMs?: number): Promise<unknown> {
const info = await this.locate(selector, timeoutMs); const info = await this.locate(selector, timeoutMs);
this.win.show();
this.win.focus();
await this.mouseClick(info.rect.x + info.rect.width / 2, info.rect.y + info.rect.height / 2); await this.mouseClick(info.rect.x + info.rect.width / 2, info.rect.y + info.rect.height / 2);
const focused = await this.withElement<boolean>(selector, `
el.focus({ focusVisible: true });
return document.activeElement === el || el.contains(document.activeElement);
`);
if (!focused) {
const direct = await this.setValueDirect(selector, clearFirst ? text : `${info.value || ""}${text}`);
return { selector: info.selector, value: direct };
}
if (clearFirst) { if (clearFirst) {
await this.cdp("Input.dispatchKeyEvent", { type: "rawKeyDown", key: "a", code: "KeyA", windowsVirtualKeyCode: 65, modifiers: 2 }); await this.cdp("Input.dispatchKeyEvent", { type: "rawKeyDown", key: "a", code: "KeyA", windowsVirtualKeyCode: 65, modifiers: 2 });
await this.cdp("Input.dispatchKeyEvent", { type: "keyUp", key: "a", code: "KeyA", windowsVirtualKeyCode: 65, modifiers: 2 }); await this.cdp("Input.dispatchKeyEvent", { type: "keyUp", key: "a", code: "KeyA", windowsVirtualKeyCode: 65, modifiers: 2 });
@ -400,11 +410,32 @@ export class BrowserSession implements BrowserLike {
await this.cdp("Input.insertText", { text }); await this.cdp("Input.insertText", { text });
await new Promise((resolve) => setTimeout(resolve, 120)); await new Promise((resolve) => setTimeout(resolve, 120));
const expected = clearFirst ? text : `${info.value || ""}${text}`; const expected = clearFirst ? text : `${info.value || ""}${text}`;
const actual = await this.evaluate<string>(`(() => { const el = document.activeElement; return el ? (el.value ?? el.textContent ?? '') : ''; })()`); const actual = await this.withElement<string>(selector, `return String(el.value ?? el.textContent ?? '')`);
if (actual !== expected) throw new RuntimeError("evaluate_error", `输入校验失败:期望「${expected}」,实际「${actual}」`, { recommendation: "检查输入框状态或重新拾取元素" }); if (actual !== expected) {
const fallback = await this.setValueDirect(selector, clearFirst ? text : expected);
if (fallback !== expected) {
throw new RuntimeError("evaluate_error", `输入校验失败:期望「${expected}」,实际「${fallback}」`, { recommendation: "检查输入框状态或重新拾取元素" });
}
return { selector: info.selector, value: fallback };
}
return { selector: info.selector, value: actual }; return { selector: info.selector, value: actual };
} }
private async setValueDirect(selector: unknown, text: string): Promise<string> {
return this.withElement<string>(selector, `
if (el.isContentEditable) {
el.textContent = ${JSON.stringify(text)};
} else {
const prototype = el instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
const descriptor = Object.getOwnPropertyDescriptor(prototype, 'value');
descriptor?.set?.call(el, ${JSON.stringify(text)});
}
el.dispatchEvent(new Event('input', { bubbles: true }));
el.dispatchEvent(new Event('change', { bubbles: true }));
return String(el.value ?? el.textContent ?? '');
`);
}
async getText(selector: unknown, attribute?: string): Promise<string> { async getText(selector: unknown, attribute?: string): Promise<string> {
const info = await this.locate(selector); const info = await this.locate(selector);
if (attribute) { if (attribute) {