@browserbasehq/orca 3.4.0-preview-2 → 3.4.0-preview-4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js +10 -0
- package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
- package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js +1 -0
- package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
- package/dist/cjs/lib/v3/types/private/snapshot.d.ts +2 -0
- package/dist/cjs/lib/v3/types/private/snapshot.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/a11yTree.js +25 -0
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/a11yTree.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/treeFormatUtils.js +10 -1
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/treeFormatUtils.js.map +1 -1
- package/dist/cjs/lib/version.d.ts +1 -1
- package/dist/cjs/lib/version.js +1 -1
- package/dist/cjs/lib/version.js.map +1 -1
- package/dist/cjs/tests/unit/anthropic-cua-triple-click.test.d.ts +1 -0
- package/dist/cjs/tests/unit/anthropic-cua-triple-click.test.js +87 -0
- package/dist/cjs/tests/unit/anthropic-cua-triple-click.test.js.map +1 -0
- package/dist/cjs/tests/unit/snapshot-a11y-tree-utils.test.js +33 -0
- package/dist/cjs/tests/unit/snapshot-a11y-tree-utils.test.js.map +1 -1
- package/dist/cjs/tests/unit/snapshot-tree-format-utils.test.js +43 -0
- package/dist/cjs/tests/unit/snapshot-tree-format-utils.test.js.map +1 -1
- package/dist/esm/lib/v3/agent/AnthropicCUAClient.js +10 -0
- package/dist/esm/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
- package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js +1 -0
- package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
- package/dist/esm/lib/v3/types/private/snapshot.d.ts +2 -0
- package/dist/esm/lib/v3/types/private/snapshot.js.map +1 -1
- package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js +25 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js.map +1 -1
- package/dist/esm/lib/v3/understudy/a11y/snapshot/treeFormatUtils.js +10 -1
- package/dist/esm/lib/v3/understudy/a11y/snapshot/treeFormatUtils.js.map +1 -1
- package/dist/esm/lib/version.d.ts +1 -1
- package/dist/esm/lib/version.js +1 -1
- package/dist/esm/lib/version.js.map +1 -1
- package/dist/esm/tests/unit/anthropic-cua-triple-click.test.d.ts +1 -0
- package/dist/esm/tests/unit/anthropic-cua-triple-click.test.js +82 -0
- package/dist/esm/tests/unit/anthropic-cua-triple-click.test.js.map +1 -0
- package/dist/esm/tests/unit/snapshot-a11y-tree-utils.test.js +33 -0
- package/dist/esm/tests/unit/snapshot-a11y-tree-utils.test.js.map +1 -1
- package/dist/esm/tests/unit/snapshot-tree-format-utils.test.js +43 -0
- package/dist/esm/tests/unit/snapshot-tree-format-utils.test.js.map +1 -1
- package/package.json +27 -14
|
@@ -125,6 +125,8 @@ function decorateRoles(nodes, opts) {
|
|
|
125
125
|
name: n.name?.value,
|
|
126
126
|
description: n.description?.value,
|
|
127
127
|
value: n.value?.value,
|
|
128
|
+
selected: extractBooleanProperty(n, "selected"),
|
|
129
|
+
checked: extractBooleanProperty(n, "checked"),
|
|
128
130
|
nodeId: n.nodeId,
|
|
129
131
|
backendDOMNodeId: n.backendDOMNodeId,
|
|
130
132
|
parentId: n.parentId,
|
|
@@ -195,6 +197,29 @@ function extractUrlFromAXNode(ax) {
|
|
|
195
197
|
const value = urlProp?.value?.value;
|
|
196
198
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
197
199
|
}
|
|
200
|
+
function toBooleanValue(value) {
|
|
201
|
+
if (typeof value === "boolean")
|
|
202
|
+
return value;
|
|
203
|
+
if (typeof value === "number") {
|
|
204
|
+
if (value === 1)
|
|
205
|
+
return true;
|
|
206
|
+
if (value === 0)
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
if (typeof value === "string") {
|
|
210
|
+
const normalized = value.toLowerCase();
|
|
211
|
+
if (normalized === "true")
|
|
212
|
+
return true;
|
|
213
|
+
if (normalized === "false")
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
function extractBooleanProperty(node, propertyName) {
|
|
219
|
+
const value = node.properties?.find((p) => p.name === propertyName)?.value
|
|
220
|
+
?.value;
|
|
221
|
+
return toBooleanValue(value);
|
|
222
|
+
}
|
|
198
223
|
function removeRedundantStaticTextChildren(parent, children) {
|
|
199
224
|
if (!parent.name)
|
|
200
225
|
return children;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a11yTree.js","sourceRoot":"","sources":["../../../../../../../lib/v3/understudy/a11y/snapshot/a11yTree.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Protocol } from \"devtools-protocol\";\nimport type { CDPSessionLike } from \"../../cdp.js\";\nimport type {\n A11yNode,\n A11yOptions,\n AccessibilityTreeResult,\n} from \"../../../types/private/snapshot.js\";\nimport {\n resolveObjectIdForCss,\n resolveObjectIdForXPath,\n} from \"./focusSelectors.js\";\nimport { formatTreeLine, normaliseSpaces } from \"./treeFormatUtils.js\";\n\n/**\n * Fetch and prune the accessibility tree for a frame, optionally scoping the\n * output to a selector root for faster targeted snapshots.\n */\nexport async function a11yForFrame(\n session: CDPSessionLike,\n frameId: string | undefined,\n opts: A11yOptions,\n): Promise<AccessibilityTreeResult> {\n await session.send(\"Accessibility.enable\").catch(() => {});\n await session.send(\"Runtime.enable\").catch(() => {});\n await session.send(\"DOM.enable\").catch(() => {});\n\n let nodes: Protocol.Accessibility.AXNode[] = [];\n try {\n const params = frameId ? ({ frameId } as Record<string, unknown>) : {};\n ({ nodes } = await session.send<{\n nodes: Protocol.Accessibility.AXNode[];\n }>(\"Accessibility.getFullAXTree\", params));\n } catch (e) {\n const msg = String((e as Error)?.message ?? e ?? \"\");\n const isFrameScopeError =\n msg.includes(\"Frame with the given\") ||\n msg.includes(\"does not belong to the target\") ||\n msg.includes(\"is not found\");\n if (!isFrameScopeError || !frameId) throw e;\n ({ nodes } = await session.send<{\n nodes: Protocol.Accessibility.AXNode[];\n }>(\"Accessibility.getFullAXTree\"));\n }\n\n let scopeApplied = false;\n const nodesForOutline = await (async () => {\n const sel = opts.focusSelector?.trim();\n if (!sel) return nodes;\n try {\n const looksLikeXPath = /^xpath=/i.test(sel) || sel.startsWith(\"/\");\n const objectId = looksLikeXPath\n ? await resolveObjectIdForXPath(session, sel, frameId)\n : await resolveObjectIdForCss(session, sel, frameId);\n if (!objectId) return nodes;\n const desc = await session.send<{ node?: { backendNodeId?: number } }>(\n \"DOM.describeNode\",\n { objectId },\n );\n const be = desc.node?.backendNodeId;\n if (typeof be !== \"number\") return nodes;\n const target = nodes.find((n) => n.backendDOMNodeId === be);\n if (!target) return nodes;\n scopeApplied = true;\n const keep = new Set<string>([target.nodeId]);\n const queue: Protocol.Accessibility.AXNode[] = [target];\n while (queue.length) {\n const cur = queue.shift()!;\n for (const id of cur.childIds ?? []) {\n if (keep.has(id)) continue;\n keep.add(id);\n const child = nodes.find((n) => n.nodeId === id);\n if (child) queue.push(child);\n }\n }\n return nodes\n .filter((n) => keep.has(n.nodeId))\n .map((n) =>\n n.nodeId === target.nodeId ? { ...n, parentId: undefined } : n,\n );\n } catch {\n return nodes;\n }\n })();\n\n const filteredNodes = nodesForOutline.filter((node) => {\n const be = node.backendDOMNodeId;\n return typeof be !== \"number\" || !opts.isIgnoredBackendNode?.(be);\n });\n\n const urlMap: Record<string, string> = {};\n for (const n of filteredNodes) {\n const be = n.backendDOMNodeId;\n if (typeof be !== \"number\") continue;\n const url = extractUrlFromAXNode(n);\n if (!url) continue;\n const enc = opts.encode(be);\n urlMap[enc] = url;\n }\n\n const decorated = decorateRoles(filteredNodes, opts);\n const { tree } = await buildHierarchicalTree(decorated, opts);\n\n const simplified = tree.map((n) => formatTreeLine(n)).join(\"\\n\");\n return { outline: simplified.trimEnd(), urlMap, scopeApplied };\n}\n\nexport function decorateRoles(\n nodes: Protocol.Accessibility.AXNode[],\n opts: A11yOptions,\n): A11yNode[] {\n const asRole = (n: Protocol.Accessibility.AXNode) =>\n String(n.role?.value ?? \"\");\n\n return nodes.map((n) => {\n let encodedId: string | undefined;\n if (typeof n.backendDOMNodeId === \"number\") {\n try {\n encodedId = opts.encode(n.backendDOMNodeId);\n } catch {\n //\n }\n }\n\n let role = asRole(n);\n\n const domIsScrollable = encodedId\n ? opts.scrollableMap[encodedId] === true\n : false;\n const tag = encodedId ? opts.tagNameMap[encodedId] : undefined;\n const isHtmlElement = tag === \"html\";\n if ((domIsScrollable || isHtmlElement) && tag !== \"#document\") {\n const tagLabel = tag && tag.startsWith(\"#\") ? tag.slice(1) : tag;\n role = tagLabel\n ? `scrollable, ${tagLabel}`\n : `scrollable${role ? `, ${role}` : \"\"}`;\n }\n\n // File inputs typically get role \"button\" from Chrome's AX tree;\n // override so they appear as \"input, file\" in the outline.\n if (tag === \"input, file\") {\n role = tag;\n }\n\n return {\n role,\n name: n.name?.value,\n description: n.description?.value,\n value: n.value?.value,\n nodeId: n.nodeId,\n backendDOMNodeId: n.backendDOMNodeId,\n parentId: n.parentId,\n childIds: n.childIds,\n encodedId,\n };\n });\n}\n\nexport async function buildHierarchicalTree(\n nodes: A11yNode[],\n opts: A11yOptions,\n): Promise<{ tree: A11yNode[] }> {\n const nodeMap = new Map<string, A11yNode>();\n\n for (const n of nodes) {\n const keep =\n !!(n.name && n.name.trim()) ||\n !!(n.childIds && n.childIds.length) ||\n !isStructural(n.role);\n if (!keep) continue;\n nodeMap.set(n.nodeId, { ...n });\n }\n\n for (const n of nodes) {\n if (!n.parentId) continue;\n const parent = nodeMap.get(n.parentId);\n const cur = nodeMap.get(n.nodeId);\n if (parent && cur) (parent.children ??= []).push(cur);\n }\n\n const roots = nodes\n .filter((n) => !n.parentId && nodeMap.has(n.nodeId))\n .map((n) => nodeMap.get(n.nodeId)!) as A11yNode[];\n\n const cleaned = (await Promise.all(roots.map(pruneStructuralSafe))).filter(\n Boolean,\n ) as A11yNode[];\n\n return { tree: cleaned };\n\n async function pruneStructuralSafe(node: A11yNode): Promise<A11yNode | null> {\n if (+node.nodeId < 0) return null;\n\n const children = node.children ?? [];\n if (!children.length) {\n return isStructural(node.role) ? null : node;\n }\n\n const cleanedKids = (\n await Promise.all(children.map(pruneStructuralSafe))\n ).filter(Boolean) as A11yNode[];\n\n const prunedStatic = removeRedundantStaticTextChildren(node, cleanedKids);\n\n if (isStructural(node.role)) {\n if (prunedStatic.length === 1) return prunedStatic[0]!;\n if (prunedStatic.length === 0) return null;\n }\n\n let newRole = node.role;\n if ((newRole === \"generic\" || newRole === \"none\") && node.encodedId) {\n const tagName = opts.tagNameMap[node.encodedId];\n if (tagName) newRole = tagName;\n }\n\n if (newRole === \"combobox\" && node.encodedId) {\n const tagName = opts.tagNameMap[node.encodedId];\n if (tagName === \"select\") newRole = \"select\";\n }\n\n return { ...node, role: newRole, children: prunedStatic };\n }\n}\n\nexport function isStructural(role: string): boolean {\n const r = role?.toLowerCase();\n return r === \"generic\" || r === \"none\" || r === \"inlinetextbox\";\n}\n\nexport function extractUrlFromAXNode(\n ax: Protocol.Accessibility.AXNode,\n): string | undefined {\n const props = ax.properties ?? [];\n const urlProp = props.find((p) => p.name === \"url\");\n const value = urlProp?.value?.value;\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nexport function removeRedundantStaticTextChildren(\n parent: A11yNode,\n children: A11yNode[],\n): A11yNode[] {\n if (!parent.name) return children;\n const parentNorm = normaliseSpaces(parent.name).trim();\n let combined = \"\";\n for (const c of children) {\n if (c.role === \"StaticText\" && c.name) {\n combined += normaliseSpaces(c.name).trim();\n }\n }\n if (combined === parentNorm) {\n return children.filter((c) => c.role !== \"StaticText\");\n }\n return children;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"a11yTree.js","sourceRoot":"","sources":["../../../../../../../lib/v3/understudy/a11y/snapshot/a11yTree.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Protocol } from \"devtools-protocol\";\nimport type { CDPSessionLike } from \"../../cdp.js\";\nimport type {\n A11yNode,\n A11yOptions,\n AccessibilityTreeResult,\n} from \"../../../types/private/snapshot.js\";\nimport {\n resolveObjectIdForCss,\n resolveObjectIdForXPath,\n} from \"./focusSelectors.js\";\nimport { formatTreeLine, normaliseSpaces } from \"./treeFormatUtils.js\";\n\n/**\n * Fetch and prune the accessibility tree for a frame, optionally scoping the\n * output to a selector root for faster targeted snapshots.\n */\nexport async function a11yForFrame(\n session: CDPSessionLike,\n frameId: string | undefined,\n opts: A11yOptions,\n): Promise<AccessibilityTreeResult> {\n await session.send(\"Accessibility.enable\").catch(() => {});\n await session.send(\"Runtime.enable\").catch(() => {});\n await session.send(\"DOM.enable\").catch(() => {});\n\n let nodes: Protocol.Accessibility.AXNode[] = [];\n try {\n const params = frameId ? ({ frameId } as Record<string, unknown>) : {};\n ({ nodes } = await session.send<{\n nodes: Protocol.Accessibility.AXNode[];\n }>(\"Accessibility.getFullAXTree\", params));\n } catch (e) {\n const msg = String((e as Error)?.message ?? e ?? \"\");\n const isFrameScopeError =\n msg.includes(\"Frame with the given\") ||\n msg.includes(\"does not belong to the target\") ||\n msg.includes(\"is not found\");\n if (!isFrameScopeError || !frameId) throw e;\n ({ nodes } = await session.send<{\n nodes: Protocol.Accessibility.AXNode[];\n }>(\"Accessibility.getFullAXTree\"));\n }\n\n let scopeApplied = false;\n const nodesForOutline = await (async () => {\n const sel = opts.focusSelector?.trim();\n if (!sel) return nodes;\n try {\n const looksLikeXPath = /^xpath=/i.test(sel) || sel.startsWith(\"/\");\n const objectId = looksLikeXPath\n ? await resolveObjectIdForXPath(session, sel, frameId)\n : await resolveObjectIdForCss(session, sel, frameId);\n if (!objectId) return nodes;\n const desc = await session.send<{ node?: { backendNodeId?: number } }>(\n \"DOM.describeNode\",\n { objectId },\n );\n const be = desc.node?.backendNodeId;\n if (typeof be !== \"number\") return nodes;\n const target = nodes.find((n) => n.backendDOMNodeId === be);\n if (!target) return nodes;\n scopeApplied = true;\n const keep = new Set<string>([target.nodeId]);\n const queue: Protocol.Accessibility.AXNode[] = [target];\n while (queue.length) {\n const cur = queue.shift()!;\n for (const id of cur.childIds ?? []) {\n if (keep.has(id)) continue;\n keep.add(id);\n const child = nodes.find((n) => n.nodeId === id);\n if (child) queue.push(child);\n }\n }\n return nodes\n .filter((n) => keep.has(n.nodeId))\n .map((n) =>\n n.nodeId === target.nodeId ? { ...n, parentId: undefined } : n,\n );\n } catch {\n return nodes;\n }\n })();\n\n const filteredNodes = nodesForOutline.filter((node) => {\n const be = node.backendDOMNodeId;\n return typeof be !== \"number\" || !opts.isIgnoredBackendNode?.(be);\n });\n\n const urlMap: Record<string, string> = {};\n for (const n of filteredNodes) {\n const be = n.backendDOMNodeId;\n if (typeof be !== \"number\") continue;\n const url = extractUrlFromAXNode(n);\n if (!url) continue;\n const enc = opts.encode(be);\n urlMap[enc] = url;\n }\n\n const decorated = decorateRoles(filteredNodes, opts);\n const { tree } = await buildHierarchicalTree(decorated, opts);\n\n const simplified = tree.map((n) => formatTreeLine(n)).join(\"\\n\");\n return { outline: simplified.trimEnd(), urlMap, scopeApplied };\n}\n\nexport function decorateRoles(\n nodes: Protocol.Accessibility.AXNode[],\n opts: A11yOptions,\n): A11yNode[] {\n const asRole = (n: Protocol.Accessibility.AXNode) =>\n String(n.role?.value ?? \"\");\n\n return nodes.map((n) => {\n let encodedId: string | undefined;\n if (typeof n.backendDOMNodeId === \"number\") {\n try {\n encodedId = opts.encode(n.backendDOMNodeId);\n } catch {\n //\n }\n }\n\n let role = asRole(n);\n\n const domIsScrollable = encodedId\n ? opts.scrollableMap[encodedId] === true\n : false;\n const tag = encodedId ? opts.tagNameMap[encodedId] : undefined;\n const isHtmlElement = tag === \"html\";\n if ((domIsScrollable || isHtmlElement) && tag !== \"#document\") {\n const tagLabel = tag && tag.startsWith(\"#\") ? tag.slice(1) : tag;\n role = tagLabel\n ? `scrollable, ${tagLabel}`\n : `scrollable${role ? `, ${role}` : \"\"}`;\n }\n\n // File inputs typically get role \"button\" from Chrome's AX tree;\n // override so they appear as \"input, file\" in the outline.\n if (tag === \"input, file\") {\n role = tag;\n }\n\n return {\n role,\n name: n.name?.value,\n description: n.description?.value,\n value: n.value?.value,\n selected: extractBooleanProperty(n, \"selected\"),\n checked: extractBooleanProperty(n, \"checked\"),\n nodeId: n.nodeId,\n backendDOMNodeId: n.backendDOMNodeId,\n parentId: n.parentId,\n childIds: n.childIds,\n encodedId,\n };\n });\n}\n\nexport async function buildHierarchicalTree(\n nodes: A11yNode[],\n opts: A11yOptions,\n): Promise<{ tree: A11yNode[] }> {\n const nodeMap = new Map<string, A11yNode>();\n\n for (const n of nodes) {\n const keep =\n !!(n.name && n.name.trim()) ||\n !!(n.childIds && n.childIds.length) ||\n !isStructural(n.role);\n if (!keep) continue;\n nodeMap.set(n.nodeId, { ...n });\n }\n\n for (const n of nodes) {\n if (!n.parentId) continue;\n const parent = nodeMap.get(n.parentId);\n const cur = nodeMap.get(n.nodeId);\n if (parent && cur) (parent.children ??= []).push(cur);\n }\n\n const roots = nodes\n .filter((n) => !n.parentId && nodeMap.has(n.nodeId))\n .map((n) => nodeMap.get(n.nodeId)!) as A11yNode[];\n\n const cleaned = (await Promise.all(roots.map(pruneStructuralSafe))).filter(\n Boolean,\n ) as A11yNode[];\n\n return { tree: cleaned };\n\n async function pruneStructuralSafe(node: A11yNode): Promise<A11yNode | null> {\n if (+node.nodeId < 0) return null;\n\n const children = node.children ?? [];\n if (!children.length) {\n return isStructural(node.role) ? null : node;\n }\n\n const cleanedKids = (\n await Promise.all(children.map(pruneStructuralSafe))\n ).filter(Boolean) as A11yNode[];\n\n const prunedStatic = removeRedundantStaticTextChildren(node, cleanedKids);\n\n if (isStructural(node.role)) {\n if (prunedStatic.length === 1) return prunedStatic[0]!;\n if (prunedStatic.length === 0) return null;\n }\n\n let newRole = node.role;\n if ((newRole === \"generic\" || newRole === \"none\") && node.encodedId) {\n const tagName = opts.tagNameMap[node.encodedId];\n if (tagName) newRole = tagName;\n }\n\n if (newRole === \"combobox\" && node.encodedId) {\n const tagName = opts.tagNameMap[node.encodedId];\n if (tagName === \"select\") newRole = \"select\";\n }\n\n return { ...node, role: newRole, children: prunedStatic };\n }\n}\n\nexport function isStructural(role: string): boolean {\n const r = role?.toLowerCase();\n return r === \"generic\" || r === \"none\" || r === \"inlinetextbox\";\n}\n\nexport function extractUrlFromAXNode(\n ax: Protocol.Accessibility.AXNode,\n): string | undefined {\n const props = ax.properties ?? [];\n const urlProp = props.find((p) => p.name === \"url\");\n const value = urlProp?.value?.value;\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\nfunction toBooleanValue(value: unknown): boolean | undefined {\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"number\") {\n if (value === 1) return true;\n if (value === 0) return false;\n }\n if (typeof value === \"string\") {\n const normalized = value.toLowerCase();\n if (normalized === \"true\") return true;\n if (normalized === \"false\") return false;\n }\n return undefined;\n}\n\nfunction extractBooleanProperty(\n node: Protocol.Accessibility.AXNode,\n propertyName: string,\n): boolean | undefined {\n const value = node.properties?.find((p) => p.name === propertyName)?.value\n ?.value;\n return toBooleanValue(value);\n}\n\nexport function removeRedundantStaticTextChildren(\n parent: A11yNode,\n children: A11yNode[],\n): A11yNode[] {\n if (!parent.name) return children;\n const parentNorm = normaliseSpaces(parent.name).trim();\n let combined = \"\";\n for (const c of children) {\n if (c.role === \"StaticText\" && c.name) {\n combined += normaliseSpaces(c.name).trim();\n }\n }\n if (combined === parentNorm) {\n return children.filter((c) => c.role !== \"StaticText\");\n }\n return children;\n}\n"]}
|
|
@@ -14,10 +14,19 @@ exports.normaliseSpaces = normaliseSpaces;
|
|
|
14
14
|
function formatTreeLine(node, level = 0) {
|
|
15
15
|
const indent = " ".repeat(level);
|
|
16
16
|
const labelId = node.encodedId ?? node.nodeId;
|
|
17
|
-
const
|
|
17
|
+
const stateFlags = formatStateFlags(node);
|
|
18
|
+
const label = `[${labelId}] ${node.role}${node.name ? `: ${cleanText(node.name)}` : ""}${stateFlags}`;
|
|
18
19
|
const kids = node.children?.map((c) => formatTreeLine(c, level + 1)).join("\n") ?? "";
|
|
19
20
|
return kids ? `${indent}${label}\n${kids}` : `${indent}${label}`;
|
|
20
21
|
}
|
|
22
|
+
function formatStateFlags(node) {
|
|
23
|
+
let flags = "";
|
|
24
|
+
if (node.selected)
|
|
25
|
+
flags += " [selected]";
|
|
26
|
+
if (node.checked)
|
|
27
|
+
flags += " [checked]";
|
|
28
|
+
return flags;
|
|
29
|
+
}
|
|
21
30
|
/**
|
|
22
31
|
* Inject each child frame outline under the parent's iframe node line.
|
|
23
32
|
* Keys in `idToTree` are the parent's iframe encoded ids.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"treeFormatUtils.js","sourceRoot":"","sources":["../../../../../../../lib/v3/understudy/a11y/snapshot/treeFormatUtils.ts"],"names":[],"mappings":";;AAOA,
|
|
1
|
+
{"version":3,"file":"treeFormatUtils.js","sourceRoot":"","sources":["../../../../../../../lib/v3/understudy/a11y/snapshot/treeFormatUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { A11yNode } from \"../../../types/private/snapshot.js\";\n\n/**\n * Render a formatted outline (with encoded ids) for the accessibility tree.\n * Keeps indentation logic shared between modules so unit tests can cover these\n * pure formatting helpers without a full snapshot pipeline.\n */\nexport function formatTreeLine(node: A11yNode, level = 0): string {\n const indent = \" \".repeat(level);\n const labelId = node.encodedId ?? node.nodeId;\n const stateFlags = formatStateFlags(node);\n const label = `[${labelId}] ${node.role}${node.name ? `: ${cleanText(node.name)}` : \"\"}${stateFlags}`;\n const kids =\n node.children?.map((c) => formatTreeLine(c, level + 1)).join(\"\\n\") ?? \"\";\n return kids ? `${indent}${label}\\n${kids}` : `${indent}${label}`;\n}\n\nfunction formatStateFlags(node: A11yNode): string {\n let flags = \"\";\n if (node.selected) flags += \" [selected]\";\n if (node.checked) flags += \" [checked]\";\n return flags;\n}\n\n/**\n * Inject each child frame outline under the parent's iframe node line.\n * Keys in `idToTree` are the parent's iframe encoded ids.\n */\nexport function injectSubtrees(\n rootOutline: string,\n idToTree: Map<string, string>,\n): string {\n type Frame = { lines: string[]; i: number };\n const out: string[] = [];\n const visited = new Set<string>();\n const stack: Frame[] = [{ lines: rootOutline.split(\"\\n\"), i: 0 }];\n\n while (stack.length) {\n const top = stack[stack.length - 1];\n if (top.i >= top.lines.length) {\n stack.pop();\n continue;\n }\n\n const raw = top.lines[top.i++];\n out.push(raw);\n\n const indent = raw.match(/^(\\s*)/)?.[1] ?? \"\";\n const content = raw.slice(indent.length);\n\n const m = content.match(/^\\[([^\\]]+)]/);\n if (!m) continue;\n\n const encId = m[1]!;\n const childOutline = idToTree.get(encId);\n if (!childOutline || visited.has(encId)) continue;\n\n visited.add(encId);\n\n const fullyInjectedChild = injectSubtrees(childOutline, idToTree);\n out.push(indentBlock(fullyInjectedChild.trimEnd(), indent + \" \"));\n }\n\n return out.join(\"\\n\");\n}\n\nexport function indentBlock(block: string, indent: string): string {\n if (!block) return \"\";\n return block\n .split(\"\\n\")\n .map((line) => (line.length ? indent + line : indent + line))\n .join(\"\\n\");\n}\n\n/**\n * Return the lines that appear in `nextTree` but not in `prevTree`.\n * Comparison is done line-by-line, ignoring leading whitespace in both trees.\n * The returned block is re-indented so the minimal indent becomes column 0.\n */\nexport function diffCombinedTrees(prevTree: string, nextTree: string): string {\n const prevSet = new Set(\n (prevTree || \"\")\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0),\n );\n\n const nextLines = (nextTree || \"\").split(\"\\n\");\n const added: string[] = [];\n for (const line of nextLines) {\n const core = line.trim();\n if (!core) continue;\n if (!prevSet.has(core)) added.push(line);\n }\n\n if (added.length === 0) return \"\";\n\n let minIndent = Infinity;\n for (const l of added) {\n if (!l.trim()) continue;\n const m = l.match(/^\\s*/);\n const indentLen = m ? m[0]!.length : 0;\n if (indentLen < minIndent) minIndent = indentLen;\n }\n if (!isFinite(minIndent)) minIndent = 0;\n\n const out = added.map((l) =>\n l.length >= minIndent ? l.slice(minIndent) : l,\n );\n return out.join(\"\\n\");\n}\n\n/**\n * Remove whitespace noise and invisible code points before rendering names.\n */\nexport function cleanText(input: string): string {\n const PUA_START = 0xe000;\n const PUA_END = 0xf8ff;\n const NBSP = new Set<number>([0x00a0, 0x202f, 0x2007, 0xfeff]);\n\n let out = \"\";\n let prevSpace = false;\n for (let i = 0; i < input.length; i++) {\n const code = input.charCodeAt(i);\n if (code >= PUA_START && code <= PUA_END) continue;\n if (NBSP.has(code)) {\n if (!prevSpace) {\n out += \" \";\n prevSpace = true;\n }\n continue;\n }\n out += input[i];\n prevSpace = input[i] === \" \";\n }\n return out.trim();\n}\n\n/**\n * Collapse all whitespace runs in a string to a single space without trimming.\n * Exported for pruning routines that need the same normalization.\n */\nexport function normaliseSpaces(s: string): string {\n let out = \"\";\n let inWs = false;\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]!;\n const isWs = /\\s/.test(ch);\n if (isWs) {\n if (!inWs) {\n out += \" \";\n inWs = true;\n }\n } else {\n out += ch;\n inWs = false;\n }\n }\n return out;\n}\n"]}
|
package/dist/cjs/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../lib/version.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,iBAAiB,GAAG,OAAgB,CAAC","sourcesContent":["/**\n * AUTO-GENERATED — DO NOT EDIT BY HAND\n * Run `pnpm run gen-version` to refresh.\n */\nexport const STAGEHAND_VERSION = \"3.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../lib/version.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,iBAAiB,GAAG,OAAgB,CAAC","sourcesContent":["/**\n * AUTO-GENERATED — DO NOT EDIT BY HAND\n * Run `pnpm run gen-version` to refresh.\n */\nexport const STAGEHAND_VERSION = \"3.4.0\" as const;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const AnthropicCUAClient_js_1 = require("../../lib/v3/agent/AnthropicCUAClient.js");
|
|
8
|
+
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
9
|
+
vitest_1.vi.mock("@anthropic-ai/sdk", () => {
|
|
10
|
+
const mockCreate = vitest_1.vi.fn();
|
|
11
|
+
return {
|
|
12
|
+
default: class MockAnthropic {
|
|
13
|
+
beta = {
|
|
14
|
+
messages: {
|
|
15
|
+
create: mockCreate,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
(0, vitest_1.describe)("AnthropicCUAClient triple_click handling", () => {
|
|
22
|
+
let mockCreate;
|
|
23
|
+
let client;
|
|
24
|
+
let executedActions;
|
|
25
|
+
(0, vitest_1.beforeEach)(() => {
|
|
26
|
+
vitest_1.vi.clearAllMocks();
|
|
27
|
+
const anthropic = new sdk_1.default({ apiKey: "test" });
|
|
28
|
+
mockCreate = anthropic.beta.messages.create;
|
|
29
|
+
client = new AnthropicCUAClient_js_1.AnthropicCUAClient("anthropic", "claude-sonnet-4-5-20250929", undefined, {
|
|
30
|
+
apiKey: "test-key",
|
|
31
|
+
});
|
|
32
|
+
client.setViewport(1280, 720);
|
|
33
|
+
client.setScreenshotProvider(async () => "fake-base64-screenshot");
|
|
34
|
+
executedActions = [];
|
|
35
|
+
client.setActionHandler(async (action) => {
|
|
36
|
+
executedActions.push({ ...action });
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
(0, vitest_1.it)("should convert triple_click with coordinate array to tripleClick action", async () => {
|
|
40
|
+
mockCreate.mockResolvedValue({
|
|
41
|
+
id: "test-id",
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
type: "tool_use",
|
|
45
|
+
id: "tool-1",
|
|
46
|
+
name: "computer",
|
|
47
|
+
input: {
|
|
48
|
+
action: "triple_click",
|
|
49
|
+
coordinate: [640, 360],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
usage: { input_tokens: 10, output_tokens: 20 },
|
|
54
|
+
});
|
|
55
|
+
const logger = vitest_1.vi.fn();
|
|
56
|
+
await client.executeStep([{ role: "user", content: "triple click the paragraph" }], logger);
|
|
57
|
+
(0, vitest_1.expect)(executedActions).toHaveLength(1);
|
|
58
|
+
(0, vitest_1.expect)(executedActions[0].type).toBe("tripleClick");
|
|
59
|
+
(0, vitest_1.expect)(executedActions[0].x).toBe(640);
|
|
60
|
+
(0, vitest_1.expect)(executedActions[0].y).toBe(360);
|
|
61
|
+
});
|
|
62
|
+
(0, vitest_1.it)("should convert triple_click with x/y fields to tripleClick action", async () => {
|
|
63
|
+
mockCreate.mockResolvedValue({
|
|
64
|
+
id: "test-id",
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "tool_use",
|
|
68
|
+
id: "tool-2",
|
|
69
|
+
name: "computer",
|
|
70
|
+
input: {
|
|
71
|
+
action: "triple_click",
|
|
72
|
+
x: 100,
|
|
73
|
+
y: 200,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
usage: { input_tokens: 10, output_tokens: 20 },
|
|
78
|
+
});
|
|
79
|
+
const logger = vitest_1.vi.fn();
|
|
80
|
+
await client.executeStep([{ role: "user", content: "triple click the line" }], logger);
|
|
81
|
+
(0, vitest_1.expect)(executedActions).toHaveLength(1);
|
|
82
|
+
(0, vitest_1.expect)(executedActions[0].type).toBe("tripleClick");
|
|
83
|
+
(0, vitest_1.expect)(executedActions[0].x).toBe(100);
|
|
84
|
+
(0, vitest_1.expect)(executedActions[0].y).toBe(200);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=anthropic-cua-triple-click.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-cua-triple-click.test.js","sourceRoot":"","sources":["../../../../tests/unit/anthropic-cua-triple-click.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it, vi, beforeEach } from \"vitest\";\nimport { AnthropicCUAClient } from \"../../lib/v3/agent/AnthropicCUAClient.js\";\nimport Anthropic from \"@anthropic-ai/sdk\";\n\nvi.mock(\"@anthropic-ai/sdk\", () => {\n const mockCreate = vi.fn();\n\n return {\n default: class MockAnthropic {\n beta = {\n messages: {\n create: mockCreate,\n },\n };\n },\n };\n});\n\ndescribe(\"AnthropicCUAClient triple_click handling\", () => {\n let mockCreate: ReturnType<typeof vi.fn>;\n let client: AnthropicCUAClient;\n let executedActions: Array<Record<string, unknown>>;\n\n beforeEach(() => {\n vi.clearAllMocks();\n const anthropic = new Anthropic({ apiKey: \"test\" });\n mockCreate = anthropic.beta.messages.create as ReturnType<typeof vi.fn>;\n\n client = new AnthropicCUAClient(\n \"anthropic\",\n \"claude-sonnet-4-5-20250929\",\n undefined,\n {\n apiKey: \"test-key\",\n },\n );\n client.setViewport(1280, 720);\n client.setScreenshotProvider(async () => \"fake-base64-screenshot\");\n\n executedActions = [];\n client.setActionHandler(async (action) => {\n executedActions.push({ ...action });\n });\n });\n\n it(\"should convert triple_click with coordinate array to tripleClick action\", async () => {\n mockCreate.mockResolvedValue({\n id: \"test-id\",\n content: [\n {\n type: \"tool_use\",\n id: \"tool-1\",\n name: \"computer\",\n input: {\n action: \"triple_click\",\n coordinate: [640, 360],\n },\n },\n ],\n usage: { input_tokens: 10, output_tokens: 20 },\n });\n\n const logger = vi.fn();\n await client.executeStep(\n [{ role: \"user\", content: \"triple click the paragraph\" }],\n logger,\n );\n\n expect(executedActions).toHaveLength(1);\n expect(executedActions[0].type).toBe(\"tripleClick\");\n expect(executedActions[0].x).toBe(640);\n expect(executedActions[0].y).toBe(360);\n });\n\n it(\"should convert triple_click with x/y fields to tripleClick action\", async () => {\n mockCreate.mockResolvedValue({\n id: \"test-id\",\n content: [\n {\n type: \"tool_use\",\n id: \"tool-2\",\n name: \"computer\",\n input: {\n action: \"triple_click\",\n x: 100,\n y: 200,\n },\n },\n ],\n usage: { input_tokens: 10, output_tokens: 20 },\n });\n\n const logger = vi.fn();\n await client.executeStep(\n [{ role: \"user\", content: \"triple click the line\" }],\n logger,\n );\n\n expect(executedActions).toHaveLength(1);\n expect(executedActions[0].type).toBe(\"tripleClick\");\n expect(executedActions[0].x).toBe(100);\n expect(executedActions[0].y).toBe(200);\n });\n});\n"]}
|
|
@@ -6,6 +6,10 @@ const axString = (value) => ({
|
|
|
6
6
|
type: "string",
|
|
7
7
|
value,
|
|
8
8
|
});
|
|
9
|
+
const axBool = (value) => ({
|
|
10
|
+
type: "boolean",
|
|
11
|
+
value,
|
|
12
|
+
});
|
|
9
13
|
const defaultOpts = {
|
|
10
14
|
focusSelector: undefined,
|
|
11
15
|
experimental: false,
|
|
@@ -94,6 +98,35 @@ const makeAxNode = (overrides = {}) => ({
|
|
|
94
98
|
const decorated = (0, a11yTree_js_1.decorateRoles)(nodes, opts);
|
|
95
99
|
(0, vitest_1.expect)(decorated[0]?.encodedId).toBeUndefined();
|
|
96
100
|
});
|
|
101
|
+
(0, vitest_1.it)("maps selected/checked AX properties into boolean fields", () => {
|
|
102
|
+
const nodes = [
|
|
103
|
+
makeAxNode({
|
|
104
|
+
backendDOMNodeId: 12,
|
|
105
|
+
role: axString("option"),
|
|
106
|
+
name: axString("Option B"),
|
|
107
|
+
properties: [{ name: "selected", value: axBool(true) }],
|
|
108
|
+
}),
|
|
109
|
+
makeAxNode({
|
|
110
|
+
backendDOMNodeId: 13,
|
|
111
|
+
role: axString("radio"),
|
|
112
|
+
name: axString("Option C"),
|
|
113
|
+
properties: [{ name: "checked", value: axBool(true) }],
|
|
114
|
+
}),
|
|
115
|
+
makeAxNode({
|
|
116
|
+
backendDOMNodeId: 14,
|
|
117
|
+
role: axString("radio"),
|
|
118
|
+
name: axString("Option D"),
|
|
119
|
+
properties: [
|
|
120
|
+
{ name: "selected", value: axBool(true) },
|
|
121
|
+
{ name: "checked", value: axBool(true) },
|
|
122
|
+
],
|
|
123
|
+
}),
|
|
124
|
+
];
|
|
125
|
+
const decorated = (0, a11yTree_js_1.decorateRoles)(nodes, defaultOpts);
|
|
126
|
+
(0, vitest_1.expect)(decorated[0]).toMatchObject({ selected: true, checked: undefined });
|
|
127
|
+
(0, vitest_1.expect)(decorated[1]).toMatchObject({ selected: undefined, checked: true });
|
|
128
|
+
(0, vitest_1.expect)(decorated[2]).toMatchObject({ selected: true, checked: true });
|
|
129
|
+
});
|
|
97
130
|
});
|
|
98
131
|
(0, vitest_1.describe)("buildHierarchicalTree", () => {
|
|
99
132
|
const opts = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot-a11y-tree-utils.test.js","sourceRoot":"","sources":["../../../../tests/unit/snapshot-a11y-tree-utils.test.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Protocol } from \"devtools-protocol\";\nimport { describe, expect, it } from \"vitest\";\nimport type {\n A11yNode,\n A11yOptions,\n} from \"../../lib/v3/types/private/snapshot.js\";\nimport {\n buildHierarchicalTree,\n decorateRoles,\n extractUrlFromAXNode,\n isStructural,\n removeRedundantStaticTextChildren,\n} from \"../../lib/v3/understudy/a11y/snapshot/a11yTree.js\";\n\nconst axString = (value: string): Protocol.Accessibility.AXValue => ({\n type: \"string\",\n value,\n});\n\nconst defaultOpts: A11yOptions = {\n focusSelector: undefined,\n experimental: false,\n tagNameMap: {},\n scrollableMap: {},\n encode: (backendNodeId: number) => `enc-${backendNodeId}`,\n};\n\nconst makeAxNode = (\n overrides: Partial<Protocol.Accessibility.AXNode> = {},\n): Protocol.Accessibility.AXNode => ({\n nodeId: overrides.nodeId ?? String(Math.random()),\n backendDOMNodeId:\n overrides.backendDOMNodeId ?? Math.floor(Math.random() * 1e6),\n role: overrides.role ?? axString(\"generic\"),\n childIds: overrides.childIds ?? [],\n parentId: overrides.parentId,\n properties: overrides.properties ?? [],\n name: overrides.name,\n description: overrides.description,\n value: overrides.value,\n ignored: overrides.ignored ?? false,\n});\n\ndescribe(\"decorateRoles\", () => {\n it(\"marks scrollable DOM nodes with tag labels and encoded ids\", () => {\n const opts: A11yOptions = {\n ...defaultOpts,\n tagNameMap: {\n \"enc-1\": \"div\",\n \"enc-2\": \"html\",\n \"enc-3\": \"#document\",\n \"enc-4\": \"#svg\",\n },\n scrollableMap: { \"enc-1\": true, \"enc-4\": true },\n };\n const nodes = [\n makeAxNode({\n backendDOMNodeId: 1,\n role: { type: \"string\", value: \"region\" },\n }),\n makeAxNode({\n backendDOMNodeId: 2,\n role: { type: \"string\", value: \"generic\" },\n }),\n makeAxNode({\n backendDOMNodeId: 3,\n role: { type: \"string\", value: \"generic\" },\n }),\n makeAxNode({\n backendDOMNodeId: 4,\n role: { type: \"string\", value: \"generic\" },\n }),\n ];\n\n const decorated = decorateRoles(nodes, opts);\n expect(decorated).toMatchObject([\n { encodedId: \"enc-1\", role: \"scrollable, div\" },\n { encodedId: \"enc-2\", role: \"scrollable, html\" },\n { encodedId: \"enc-3\", role: \"generic\" },\n { encodedId: \"enc-4\", role: \"scrollable, svg\" },\n ]);\n });\n\n it(\"overrides role to 'input, file' for file inputs\", () => {\n const opts: A11yOptions = {\n ...defaultOpts,\n tagNameMap: { \"enc-10\": \"input, file\" },\n scrollableMap: {},\n };\n const nodes = [\n makeAxNode({\n backendDOMNodeId: 10,\n role: axString(\"button\"),\n name: axString(\"Choose File\"),\n }),\n ];\n\n const decorated = decorateRoles(nodes, opts);\n expect(decorated[0]).toMatchObject({\n encodedId: \"enc-10\",\n role: \"input, file\",\n name: \"Choose File\",\n });\n });\n\n it(\"falls back when encoding fails\", () => {\n const opts: A11yOptions = {\n ...defaultOpts,\n encode: () => {\n throw new Error(\"boom\");\n },\n };\n const nodes = [makeAxNode({ backendDOMNodeId: 4 })];\n const decorated = decorateRoles(nodes, opts);\n expect(decorated[0]?.encodedId).toBeUndefined();\n });\n});\n\ndescribe(\"buildHierarchicalTree\", () => {\n const opts: A11yOptions = {\n ...defaultOpts,\n tagNameMap: { root: \"div\", child: \"span\" },\n };\n\n it(\"drops structural nodes without children or names\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child\"],\n },\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"child\",\n encodedId: \"child\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, opts);\n expect(tree).toEqual([]);\n });\n\n it(\"promotes select/combobox tag names for structural nodes\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"combobox\",\n name: \"Select\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child\"],\n },\n {\n role: \"StaticText\",\n name: \"Option\",\n nodeId: \"child\",\n encodedId: \"child\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, {\n ...opts,\n tagNameMap: { root: \"select\" },\n });\n expect(tree[0]?.role).toBe(\"select\");\n });\n\n it(\"drops structural parents with a single cleaned child while keeping it in place\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child\"],\n },\n {\n role: \"StaticText\",\n name: \"Ok\",\n nodeId: \"child\",\n encodedId: \"child\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, opts);\n expect(tree[0]?.role).toBe(\"StaticText\");\n });\n\n it(\"drops structural parents entirely when all descendants are pruned\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child\"],\n },\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"child\",\n encodedId: \"child\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, opts);\n expect(tree).toEqual([]);\n });\n\n it(\"renames structural nodes to their tag names when not combobox\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"generic\",\n name: \"Container\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child-a\", \"child-b\"],\n },\n {\n role: \"StaticText\",\n name: \"A\",\n nodeId: \"child-a\",\n encodedId: \"child-a\",\n parentId: \"root\",\n childIds: [],\n },\n {\n role: \"StaticText\",\n name: \"B\",\n nodeId: \"child-b\",\n encodedId: \"child-b\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, {\n ...opts,\n tagNameMap: { root: \"section\" },\n });\n expect(tree[0]?.role).toBe(\"section\");\n });\n\n it(\"skips nodes with negative node ids early\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"button\",\n name: \"Hidden\",\n nodeId: \"-1\",\n encodedId: \"hidden\",\n parentId: undefined,\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, opts);\n expect(tree).toEqual([]);\n });\n});\n\ndescribe(\"isStructural\", () => {\n it(\"marks generic/none/InlineTextBox roles as structural\", () => {\n expect(isStructural(\"generic\")).toBe(true);\n expect(isStructural(\"none\")).toBe(true);\n expect(isStructural(\"InlineTextBox\")).toBe(true);\n expect(isStructural(\"button\")).toBe(false);\n });\n});\n\ndescribe(\"removeRedundantStaticTextChildren\", () => {\n it(\"removes static text children whose concatenated text equals the parent name\", () => {\n const parent: A11yNode = {\n role: \"button\",\n name: \"HelloWorld\",\n nodeId: \"root\",\n };\n const children: A11yNode[] = [\n { role: \"StaticText\", name: \"Hello\", nodeId: \"c1\" },\n { role: \"StaticText\", name: \"World\", nodeId: \"c2\" },\n { role: \"button\", name: \"Child\", nodeId: \"c3\" },\n ];\n const pruned = removeRedundantStaticTextChildren(parent, children);\n expect(pruned).toEqual([{ role: \"button\", name: \"Child\", nodeId: \"c3\" }]);\n });\n\n it(\"keeps static text when combined text differs\", () => {\n const parent: A11yNode = {\n role: \"button\",\n name: \"Hello World\",\n nodeId: \"root\",\n };\n const children: A11yNode[] = [\n { role: \"StaticText\", name: \"Hello\", nodeId: \"c1\" },\n { role: \"StaticText\", name: \"Mars\", nodeId: \"c2\" },\n ];\n expect(removeRedundantStaticTextChildren(parent, children)).toEqual(\n children,\n );\n });\n it(\"returns original children when parent name is empty\", () => {\n const parent: A11yNode = {\n role: \"button\",\n nodeId: \"root\",\n };\n const children: A11yNode[] = [\n { role: \"StaticText\", name: \"Hello\", nodeId: \"c1\" },\n { role: \"StaticText\", name: \"World\", nodeId: \"c2\" },\n ];\n expect(removeRedundantStaticTextChildren(parent, children)).toEqual(\n children,\n );\n });\n});\n\ndescribe(\"extractUrlFromAXNode\", () => {\n it(\"returns trimmed URL string from node properties\", () => {\n const node = makeAxNode({\n properties: [\n { name: \"busy\", value: axString(\"bar\") },\n { name: \"url\", value: axString(\" https://example.com \") },\n ],\n });\n expect(extractUrlFromAXNode(node)).toBe(\"https://example.com\");\n });\n\n it(\"returns undefined when url property missing or invalid\", () => {\n expect(\n extractUrlFromAXNode(makeAxNode({ properties: [] })),\n ).toBeUndefined();\n expect(\n extractUrlFromAXNode(\n makeAxNode({\n properties: [{ name: \"url\", value: { type: \"number\", value: 123 } }],\n }),\n ),\n ).toBeUndefined();\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"snapshot-a11y-tree-utils.test.js","sourceRoot":"","sources":["../../../../tests/unit/snapshot-a11y-tree-utils.test.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Protocol } from \"devtools-protocol\";\nimport { describe, expect, it } from \"vitest\";\nimport type {\n A11yNode,\n A11yOptions,\n} from \"../../lib/v3/types/private/snapshot.js\";\nimport {\n buildHierarchicalTree,\n decorateRoles,\n extractUrlFromAXNode,\n isStructural,\n removeRedundantStaticTextChildren,\n} from \"../../lib/v3/understudy/a11y/snapshot/a11yTree.js\";\n\nconst axString = (value: string): Protocol.Accessibility.AXValue => ({\n type: \"string\",\n value,\n});\n\nconst axBool = (value: boolean): Protocol.Accessibility.AXValue => ({\n type: \"boolean\",\n value,\n});\n\nconst defaultOpts: A11yOptions = {\n focusSelector: undefined,\n experimental: false,\n tagNameMap: {},\n scrollableMap: {},\n encode: (backendNodeId: number) => `enc-${backendNodeId}`,\n};\n\nconst makeAxNode = (\n overrides: Partial<Protocol.Accessibility.AXNode> = {},\n): Protocol.Accessibility.AXNode => ({\n nodeId: overrides.nodeId ?? String(Math.random()),\n backendDOMNodeId:\n overrides.backendDOMNodeId ?? Math.floor(Math.random() * 1e6),\n role: overrides.role ?? axString(\"generic\"),\n childIds: overrides.childIds ?? [],\n parentId: overrides.parentId,\n properties: overrides.properties ?? [],\n name: overrides.name,\n description: overrides.description,\n value: overrides.value,\n ignored: overrides.ignored ?? false,\n});\n\ndescribe(\"decorateRoles\", () => {\n it(\"marks scrollable DOM nodes with tag labels and encoded ids\", () => {\n const opts: A11yOptions = {\n ...defaultOpts,\n tagNameMap: {\n \"enc-1\": \"div\",\n \"enc-2\": \"html\",\n \"enc-3\": \"#document\",\n \"enc-4\": \"#svg\",\n },\n scrollableMap: { \"enc-1\": true, \"enc-4\": true },\n };\n const nodes = [\n makeAxNode({\n backendDOMNodeId: 1,\n role: { type: \"string\", value: \"region\" },\n }),\n makeAxNode({\n backendDOMNodeId: 2,\n role: { type: \"string\", value: \"generic\" },\n }),\n makeAxNode({\n backendDOMNodeId: 3,\n role: { type: \"string\", value: \"generic\" },\n }),\n makeAxNode({\n backendDOMNodeId: 4,\n role: { type: \"string\", value: \"generic\" },\n }),\n ];\n\n const decorated = decorateRoles(nodes, opts);\n expect(decorated).toMatchObject([\n { encodedId: \"enc-1\", role: \"scrollable, div\" },\n { encodedId: \"enc-2\", role: \"scrollable, html\" },\n { encodedId: \"enc-3\", role: \"generic\" },\n { encodedId: \"enc-4\", role: \"scrollable, svg\" },\n ]);\n });\n\n it(\"overrides role to 'input, file' for file inputs\", () => {\n const opts: A11yOptions = {\n ...defaultOpts,\n tagNameMap: { \"enc-10\": \"input, file\" },\n scrollableMap: {},\n };\n const nodes = [\n makeAxNode({\n backendDOMNodeId: 10,\n role: axString(\"button\"),\n name: axString(\"Choose File\"),\n }),\n ];\n\n const decorated = decorateRoles(nodes, opts);\n expect(decorated[0]).toMatchObject({\n encodedId: \"enc-10\",\n role: \"input, file\",\n name: \"Choose File\",\n });\n });\n\n it(\"falls back when encoding fails\", () => {\n const opts: A11yOptions = {\n ...defaultOpts,\n encode: () => {\n throw new Error(\"boom\");\n },\n };\n const nodes = [makeAxNode({ backendDOMNodeId: 4 })];\n const decorated = decorateRoles(nodes, opts);\n expect(decorated[0]?.encodedId).toBeUndefined();\n });\n\n it(\"maps selected/checked AX properties into boolean fields\", () => {\n const nodes = [\n makeAxNode({\n backendDOMNodeId: 12,\n role: axString(\"option\"),\n name: axString(\"Option B\"),\n properties: [{ name: \"selected\", value: axBool(true) }],\n }),\n makeAxNode({\n backendDOMNodeId: 13,\n role: axString(\"radio\"),\n name: axString(\"Option C\"),\n properties: [{ name: \"checked\", value: axBool(true) }],\n }),\n makeAxNode({\n backendDOMNodeId: 14,\n role: axString(\"radio\"),\n name: axString(\"Option D\"),\n properties: [\n { name: \"selected\", value: axBool(true) },\n { name: \"checked\", value: axBool(true) },\n ],\n }),\n ];\n\n const decorated = decorateRoles(nodes, defaultOpts);\n expect(decorated[0]).toMatchObject({ selected: true, checked: undefined });\n expect(decorated[1]).toMatchObject({ selected: undefined, checked: true });\n expect(decorated[2]).toMatchObject({ selected: true, checked: true });\n });\n});\n\ndescribe(\"buildHierarchicalTree\", () => {\n const opts: A11yOptions = {\n ...defaultOpts,\n tagNameMap: { root: \"div\", child: \"span\" },\n };\n\n it(\"drops structural nodes without children or names\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child\"],\n },\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"child\",\n encodedId: \"child\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, opts);\n expect(tree).toEqual([]);\n });\n\n it(\"promotes select/combobox tag names for structural nodes\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"combobox\",\n name: \"Select\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child\"],\n },\n {\n role: \"StaticText\",\n name: \"Option\",\n nodeId: \"child\",\n encodedId: \"child\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, {\n ...opts,\n tagNameMap: { root: \"select\" },\n });\n expect(tree[0]?.role).toBe(\"select\");\n });\n\n it(\"drops structural parents with a single cleaned child while keeping it in place\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child\"],\n },\n {\n role: \"StaticText\",\n name: \"Ok\",\n nodeId: \"child\",\n encodedId: \"child\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, opts);\n expect(tree[0]?.role).toBe(\"StaticText\");\n });\n\n it(\"drops structural parents entirely when all descendants are pruned\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child\"],\n },\n {\n role: \"generic\",\n name: \"\",\n nodeId: \"child\",\n encodedId: \"child\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, opts);\n expect(tree).toEqual([]);\n });\n\n it(\"renames structural nodes to their tag names when not combobox\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"generic\",\n name: \"Container\",\n nodeId: \"root\",\n encodedId: \"root\",\n parentId: undefined,\n childIds: [\"child-a\", \"child-b\"],\n },\n {\n role: \"StaticText\",\n name: \"A\",\n nodeId: \"child-a\",\n encodedId: \"child-a\",\n parentId: \"root\",\n childIds: [],\n },\n {\n role: \"StaticText\",\n name: \"B\",\n nodeId: \"child-b\",\n encodedId: \"child-b\",\n parentId: \"root\",\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, {\n ...opts,\n tagNameMap: { root: \"section\" },\n });\n expect(tree[0]?.role).toBe(\"section\");\n });\n\n it(\"skips nodes with negative node ids early\", async () => {\n const nodes: A11yNode[] = [\n {\n role: \"button\",\n name: \"Hidden\",\n nodeId: \"-1\",\n encodedId: \"hidden\",\n parentId: undefined,\n childIds: [],\n },\n ];\n\n const { tree } = await buildHierarchicalTree(nodes, opts);\n expect(tree).toEqual([]);\n });\n});\n\ndescribe(\"isStructural\", () => {\n it(\"marks generic/none/InlineTextBox roles as structural\", () => {\n expect(isStructural(\"generic\")).toBe(true);\n expect(isStructural(\"none\")).toBe(true);\n expect(isStructural(\"InlineTextBox\")).toBe(true);\n expect(isStructural(\"button\")).toBe(false);\n });\n});\n\ndescribe(\"removeRedundantStaticTextChildren\", () => {\n it(\"removes static text children whose concatenated text equals the parent name\", () => {\n const parent: A11yNode = {\n role: \"button\",\n name: \"HelloWorld\",\n nodeId: \"root\",\n };\n const children: A11yNode[] = [\n { role: \"StaticText\", name: \"Hello\", nodeId: \"c1\" },\n { role: \"StaticText\", name: \"World\", nodeId: \"c2\" },\n { role: \"button\", name: \"Child\", nodeId: \"c3\" },\n ];\n const pruned = removeRedundantStaticTextChildren(parent, children);\n expect(pruned).toEqual([{ role: \"button\", name: \"Child\", nodeId: \"c3\" }]);\n });\n\n it(\"keeps static text when combined text differs\", () => {\n const parent: A11yNode = {\n role: \"button\",\n name: \"Hello World\",\n nodeId: \"root\",\n };\n const children: A11yNode[] = [\n { role: \"StaticText\", name: \"Hello\", nodeId: \"c1\" },\n { role: \"StaticText\", name: \"Mars\", nodeId: \"c2\" },\n ];\n expect(removeRedundantStaticTextChildren(parent, children)).toEqual(\n children,\n );\n });\n it(\"returns original children when parent name is empty\", () => {\n const parent: A11yNode = {\n role: \"button\",\n nodeId: \"root\",\n };\n const children: A11yNode[] = [\n { role: \"StaticText\", name: \"Hello\", nodeId: \"c1\" },\n { role: \"StaticText\", name: \"World\", nodeId: \"c2\" },\n ];\n expect(removeRedundantStaticTextChildren(parent, children)).toEqual(\n children,\n );\n });\n});\n\ndescribe(\"extractUrlFromAXNode\", () => {\n it(\"returns trimmed URL string from node properties\", () => {\n const node = makeAxNode({\n properties: [\n { name: \"busy\", value: axString(\"bar\") },\n { name: \"url\", value: axString(\" https://example.com \") },\n ],\n });\n expect(extractUrlFromAXNode(node)).toBe(\"https://example.com\");\n });\n\n it(\"returns undefined when url property missing or invalid\", () => {\n expect(\n extractUrlFromAXNode(makeAxNode({ properties: [] })),\n ).toBeUndefined();\n expect(\n extractUrlFromAXNode(\n makeAxNode({\n properties: [{ name: \"url\", value: { type: \"number\", value: 123 } }],\n }),\n ),\n ).toBeUndefined();\n });\n});\n"]}
|
|
@@ -19,6 +19,49 @@ const treeFormatUtils_js_1 = require("../../lib/v3/understudy/a11y/snapshot/tree
|
|
|
19
19
|
});
|
|
20
20
|
(0, vitest_1.expect)(outline).toBe("[frame-1] section: Container\n [ax-2] button: Submit");
|
|
21
21
|
});
|
|
22
|
+
(0, vitest_1.it)("renders a select with child options and only one selected option", () => {
|
|
23
|
+
const outline = (0, treeFormatUtils_js_1.formatTreeLine)({
|
|
24
|
+
role: "select",
|
|
25
|
+
name: "Select field",
|
|
26
|
+
nodeId: "ax-4",
|
|
27
|
+
children: [
|
|
28
|
+
{ role: "option", name: "Option A", nodeId: "ax-5" },
|
|
29
|
+
{
|
|
30
|
+
role: "option",
|
|
31
|
+
name: "Option B",
|
|
32
|
+
selected: true,
|
|
33
|
+
nodeId: "ax-6",
|
|
34
|
+
},
|
|
35
|
+
{ role: "option", name: "Option C", nodeId: "ax-7" },
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
(0, vitest_1.expect)(outline).toBe("[ax-4] select: Select field\n [ax-5] option: Option A\n [ax-6] option: Option B [selected]\n [ax-7] option: Option C");
|
|
39
|
+
(0, vitest_1.expect)(outline.match(/\[selected]/g)?.length ?? 0).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
(0, vitest_1.it)("renders a radio group with children and only one checked radio", () => {
|
|
42
|
+
const outline = (0, treeFormatUtils_js_1.formatTreeLine)({
|
|
43
|
+
role: "group",
|
|
44
|
+
name: "Select field",
|
|
45
|
+
nodeId: "ax-8",
|
|
46
|
+
children: [
|
|
47
|
+
{ role: "radio", name: "Option A", nodeId: "ax-9" },
|
|
48
|
+
{ role: "radio", name: "Option B", checked: true, nodeId: "ax-10" },
|
|
49
|
+
{ role: "radio", name: "Option C", nodeId: "ax-11" },
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.expect)(outline).toBe("[ax-8] group: Select field\n [ax-9] radio: Option A\n [ax-10] radio: Option B [checked]\n [ax-11] radio: Option C");
|
|
53
|
+
(0, vitest_1.expect)(outline.match(/\[checked]/g)?.length ?? 0).toBe(1);
|
|
54
|
+
});
|
|
55
|
+
(0, vitest_1.it)("renders both flags when a node carries both states", () => {
|
|
56
|
+
const outline = (0, treeFormatUtils_js_1.formatTreeLine)({
|
|
57
|
+
role: "menuitemcheckbox",
|
|
58
|
+
name: "Hybrid state",
|
|
59
|
+
selected: true,
|
|
60
|
+
checked: true,
|
|
61
|
+
nodeId: "ax-12",
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.expect)(outline).toBe("[ax-12] menuitemcheckbox: Hybrid state [selected] [checked]");
|
|
64
|
+
});
|
|
22
65
|
});
|
|
23
66
|
(0, vitest_1.describe)("injectSubtrees", () => {
|
|
24
67
|
(0, vitest_1.it)("nests child outlines under iframe encoded ids", () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot-tree-format-utils.test.js","sourceRoot":"","sources":["../../../../tests/unit/snapshot-tree-format-utils.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport {\n cleanText,\n diffCombinedTrees,\n formatTreeLine,\n indentBlock,\n injectSubtrees,\n normaliseSpaces,\n} from \"../../lib/v3/understudy/a11y/snapshot/treeFormatUtils.js\";\n\ndescribe(\"formatTreeLine\", () => {\n it(\"includes encoded ids and indents children\", () => {\n const outline = formatTreeLine({\n role: \"section\",\n name: \"Container\",\n encodedId: \"frame-1\",\n nodeId: \"ax-1\",\n children: [\n {\n role: \"button\",\n name: \"Submit\",\n nodeId: \"ax-2\",\n },\n ],\n });\n\n expect(outline).toBe(\n \"[frame-1] section: Container\\n [ax-2] button: Submit\",\n );\n });\n});\n\ndescribe(\"injectSubtrees\", () => {\n it(\"nests child outlines under iframe encoded ids\", () => {\n const rootOutline = `[root] document\\n [iframe-1] iframe\\n [leaf] item`;\n const iframeOutline = `[child-root] child\\n [nested-frame] iframe`;\n const nestedOutline = `[nested-leaf] nested`;\n\n const merged = injectSubtrees(\n rootOutline,\n new Map([\n [\"iframe-1\", iframeOutline],\n [\"nested-frame\", nestedOutline],\n ]),\n );\n\n expect(merged).toBe(\n `[root] document\n [iframe-1] iframe\n [child-root] child\n [nested-frame] iframe\n [nested-leaf] nested\n [leaf] item`,\n );\n });\n\n it(\"injects child outline only once when the same id repeats\", () => {\n const rootOutline = `[root] document\n [iframe-1] iframe\n [iframe-1] iframe`;\n const iframeOutline = `[child-root] child`;\n\n const merged = injectSubtrees(\n rootOutline,\n new Map([[\"iframe-1\", iframeOutline]]),\n );\n\n expect(merged).toBe(\n `[root] document\n [iframe-1] iframe\n [child-root] child\n [iframe-1] iframe`,\n );\n });\n\n it(\"returns the original outline when no encoded ids are matched\", () => {\n const outline = `[root] document\\n [leaf] item`;\n expect(injectSubtrees(outline, new Map([[\"other\", \"[x] child\"]]))).toBe(\n outline,\n );\n });\n});\n\ndescribe(\"indentBlock\", () => {\n it(\"prefixes each line with the provided indent\", () => {\n expect(indentBlock(\"a\\nb\", \" \")).toBe(\" a\\n b\");\n expect(indentBlock(\"\", \" \")).toBe(\"\");\n });\n});\n\ndescribe(\"diffCombinedTrees\", () => {\n it(\"returns newly-added lines relative to previous outline\", () => {\n const prev = `[root] document\\n [child] a`;\n const next = `[root] document\\n [child] a\\n [child-2] b`;\n expect(diffCombinedTrees(prev, next)).toBe(\"[child-2] b\");\n });\n\n it(\"normalizes indentation for added lines with stray spaces\", () => {\n const prev = `[root] document\\n [child] a`;\n const next = `[root] document\\n [child] a\\n [child-2] b`;\n expect(diffCombinedTrees(prev, next)).toBe(\"[child-2] b\");\n });\n});\n\ndescribe(\"cleanText\", () => {\n it(\"removes NBSP and private-use characters while collapsing spaces\", () => {\n const dirty = `Hello\\u00A0\\u00A0world\\uE000 !`;\n expect(cleanText(dirty)).toBe(\"Hello world !\");\n });\n});\n\ndescribe(\"normaliseSpaces\", () => {\n it(\"replaces whitespace runs with a single space\", () => {\n expect(normaliseSpaces(\"a b\\tc\\nd\")).toBe(\"a b c d\");\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"snapshot-tree-format-utils.test.js","sourceRoot":"","sources":["../../../../tests/unit/snapshot-tree-format-utils.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport {\n cleanText,\n diffCombinedTrees,\n formatTreeLine,\n indentBlock,\n injectSubtrees,\n normaliseSpaces,\n} from \"../../lib/v3/understudy/a11y/snapshot/treeFormatUtils.js\";\n\ndescribe(\"formatTreeLine\", () => {\n it(\"includes encoded ids and indents children\", () => {\n const outline = formatTreeLine({\n role: \"section\",\n name: \"Container\",\n encodedId: \"frame-1\",\n nodeId: \"ax-1\",\n children: [\n {\n role: \"button\",\n name: \"Submit\",\n nodeId: \"ax-2\",\n },\n ],\n });\n\n expect(outline).toBe(\n \"[frame-1] section: Container\\n [ax-2] button: Submit\",\n );\n });\n\n it(\"renders a select with child options and only one selected option\", () => {\n const outline = formatTreeLine({\n role: \"select\",\n name: \"Select field\",\n nodeId: \"ax-4\",\n children: [\n { role: \"option\", name: \"Option A\", nodeId: \"ax-5\" },\n {\n role: \"option\",\n name: \"Option B\",\n selected: true,\n nodeId: \"ax-6\",\n },\n { role: \"option\", name: \"Option C\", nodeId: \"ax-7\" },\n ],\n });\n\n expect(outline).toBe(\n \"[ax-4] select: Select field\\n [ax-5] option: Option A\\n [ax-6] option: Option B [selected]\\n [ax-7] option: Option C\",\n );\n expect(outline.match(/\\[selected]/g)?.length ?? 0).toBe(1);\n });\n\n it(\"renders a radio group with children and only one checked radio\", () => {\n const outline = formatTreeLine({\n role: \"group\",\n name: \"Select field\",\n nodeId: \"ax-8\",\n children: [\n { role: \"radio\", name: \"Option A\", nodeId: \"ax-9\" },\n { role: \"radio\", name: \"Option B\", checked: true, nodeId: \"ax-10\" },\n { role: \"radio\", name: \"Option C\", nodeId: \"ax-11\" },\n ],\n });\n\n expect(outline).toBe(\n \"[ax-8] group: Select field\\n [ax-9] radio: Option A\\n [ax-10] radio: Option B [checked]\\n [ax-11] radio: Option C\",\n );\n expect(outline.match(/\\[checked]/g)?.length ?? 0).toBe(1);\n });\n\n it(\"renders both flags when a node carries both states\", () => {\n const outline = formatTreeLine({\n role: \"menuitemcheckbox\",\n name: \"Hybrid state\",\n selected: true,\n checked: true,\n nodeId: \"ax-12\",\n });\n\n expect(outline).toBe(\n \"[ax-12] menuitemcheckbox: Hybrid state [selected] [checked]\",\n );\n });\n});\n\ndescribe(\"injectSubtrees\", () => {\n it(\"nests child outlines under iframe encoded ids\", () => {\n const rootOutline = `[root] document\\n [iframe-1] iframe\\n [leaf] item`;\n const iframeOutline = `[child-root] child\\n [nested-frame] iframe`;\n const nestedOutline = `[nested-leaf] nested`;\n\n const merged = injectSubtrees(\n rootOutline,\n new Map([\n [\"iframe-1\", iframeOutline],\n [\"nested-frame\", nestedOutline],\n ]),\n );\n\n expect(merged).toBe(\n `[root] document\n [iframe-1] iframe\n [child-root] child\n [nested-frame] iframe\n [nested-leaf] nested\n [leaf] item`,\n );\n });\n\n it(\"injects child outline only once when the same id repeats\", () => {\n const rootOutline = `[root] document\n [iframe-1] iframe\n [iframe-1] iframe`;\n const iframeOutline = `[child-root] child`;\n\n const merged = injectSubtrees(\n rootOutline,\n new Map([[\"iframe-1\", iframeOutline]]),\n );\n\n expect(merged).toBe(\n `[root] document\n [iframe-1] iframe\n [child-root] child\n [iframe-1] iframe`,\n );\n });\n\n it(\"returns the original outline when no encoded ids are matched\", () => {\n const outline = `[root] document\\n [leaf] item`;\n expect(injectSubtrees(outline, new Map([[\"other\", \"[x] child\"]]))).toBe(\n outline,\n );\n });\n});\n\ndescribe(\"indentBlock\", () => {\n it(\"prefixes each line with the provided indent\", () => {\n expect(indentBlock(\"a\\nb\", \" \")).toBe(\" a\\n b\");\n expect(indentBlock(\"\", \" \")).toBe(\"\");\n });\n});\n\ndescribe(\"diffCombinedTrees\", () => {\n it(\"returns newly-added lines relative to previous outline\", () => {\n const prev = `[root] document\\n [child] a`;\n const next = `[root] document\\n [child] a\\n [child-2] b`;\n expect(diffCombinedTrees(prev, next)).toBe(\"[child-2] b\");\n });\n\n it(\"normalizes indentation for added lines with stray spaces\", () => {\n const prev = `[root] document\\n [child] a`;\n const next = `[root] document\\n [child] a\\n [child-2] b`;\n expect(diffCombinedTrees(prev, next)).toBe(\"[child-2] b\");\n });\n});\n\ndescribe(\"cleanText\", () => {\n it(\"removes NBSP and private-use characters while collapsing spaces\", () => {\n const dirty = `Hello\\u00A0\\u00A0world\\uE000 !`;\n expect(cleanText(dirty)).toBe(\"Hello world !\");\n });\n});\n\ndescribe(\"normaliseSpaces\", () => {\n it(\"replaces whitespace runs with a single space\", () => {\n expect(normaliseSpaces(\"a b\\tc\\nd\")).toBe(\"a b c d\");\n });\n});\n"]}
|
|
@@ -746,6 +746,16 @@ export class AnthropicCUAClient extends AgentClient {
|
|
|
746
746
|
...input,
|
|
747
747
|
};
|
|
748
748
|
}
|
|
749
|
+
else if (action === "triple_click" || action === "tripleClick") {
|
|
750
|
+
return {
|
|
751
|
+
type: "tripleClick",
|
|
752
|
+
x: input.x ||
|
|
753
|
+
(input.coordinate ? input.coordinate[0] : 0),
|
|
754
|
+
y: input.y ||
|
|
755
|
+
(input.coordinate ? input.coordinate[1] : 0),
|
|
756
|
+
...input,
|
|
757
|
+
};
|
|
758
|
+
}
|
|
749
759
|
else if (action === "scroll") {
|
|
750
760
|
// Convert Anthropic's coordinate, scroll_amount and scroll_direction into scroll_x and scroll_y
|
|
751
761
|
const x = input.x ||
|