| import { parseRoleRef } from "./pw-role-snapshot.js"; |
|
|
| let nextUploadArmId = 0; |
| let nextDialogArmId = 0; |
| let nextDownloadArmId = 0; |
|
|
| export function bumpUploadArmId(): number { |
| nextUploadArmId += 1; |
| return nextUploadArmId; |
| } |
|
|
| export function bumpDialogArmId(): number { |
| nextDialogArmId += 1; |
| return nextDialogArmId; |
| } |
|
|
| export function bumpDownloadArmId(): number { |
| nextDownloadArmId += 1; |
| return nextDownloadArmId; |
| } |
|
|
| export function requireRef(value: unknown): string { |
| const raw = typeof value === "string" ? value.trim() : ""; |
| const roleRef = raw ? parseRoleRef(raw) : null; |
| const ref = roleRef ?? (raw.startsWith("@") ? raw.slice(1) : raw); |
| if (!ref) { |
| throw new Error("ref is required"); |
| } |
| return ref; |
| } |
|
|
| export function normalizeTimeoutMs(timeoutMs: number | undefined, fallback: number) { |
| return Math.max(500, Math.min(120_000, timeoutMs ?? fallback)); |
| } |
|
|
| export function toAIFriendlyError(error: unknown, selector: string): Error { |
| const message = error instanceof Error ? error.message : String(error); |
|
|
| if (message.includes("strict mode violation")) { |
| const countMatch = message.match(/resolved to (\d+) elements/); |
| const count = countMatch ? countMatch[1] : "multiple"; |
| return new Error( |
| `Selector "${selector}" matched ${count} elements. ` + |
| `Run a new snapshot to get updated refs, or use a different ref.`, |
| ); |
| } |
|
|
| if ( |
| (message.includes("Timeout") || message.includes("waiting for")) && |
| (message.includes("to be visible") || message.includes("not visible")) |
| ) { |
| return new Error( |
| `Element "${selector}" not found or not visible. ` + |
| `Run a new snapshot to see current page elements.`, |
| ); |
| } |
|
|
| if ( |
| message.includes("intercepts pointer events") || |
| message.includes("not visible") || |
| message.includes("not receive pointer events") |
| ) { |
| return new Error( |
| `Element "${selector}" is not interactable (hidden or covered). ` + |
| `Try scrolling it into view, closing overlays, or re-snapshotting.`, |
| ); |
| } |
|
|
| return error instanceof Error ? error : new Error(message); |
| } |
|
|