mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-05 04:27:09 +00:00
fix(verifier): canonicalize selector strings
Object/chain JS selectors used to fall through to goja's default stringification, producing "[object Object]" tags that surfaced as garbage in trace.action.selector. Emit canonical "k:v" / " > "-joined strings instead so the tag round-trips back through the hierarchy selector grammar.
This commit is contained in:
1 parent
09c1b8df26
commit
352118c199
2 files changed
+131
-8
No files matched your search
@@ -3,6 +3,7 @@ package verifier
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
@@ -69,7 +70,7 @@ func accessibilityObject(runtime *goja.Runtime, tree *hierarchy.Tree) *goja.Obje
|
||||
if node == nil {
|
||||
return goja.Undefined()
|
||||
}
|
||||
return nodeObject(runtime, node, selectorStringFromJS(call.Argument(0)))
|
||||
return nodeObject(runtime, node, selectorStringFromJS(runtime, call.Argument(0)))
|
||||
}
|
||||
findAll := func(call goja.FunctionCall) goja.Value {
|
||||
if tree == nil {
|
||||
@@ -78,7 +79,7 @@ func accessibilityObject(runtime *goja.Runtime, tree *hierarchy.Tree) *goja.Obje
|
||||
nodes := findAllNodesFromJS(runtime, tree, call.Argument(0))
|
||||
array := runtime.NewArray()
|
||||
for i, n := range nodes {
|
||||
_ = array.Set(fmt.Sprintf("%d", i), nodeObject(runtime, n, selectorStringFromJS(call.Argument(0))))
|
||||
_ = array.Set(fmt.Sprintf("%d", i), nodeObject(runtime, n, selectorStringFromJS(runtime, call.Argument(0))))
|
||||
}
|
||||
return array
|
||||
}
|
||||
@@ -121,14 +122,14 @@ func nodeObject(runtime *goja.Runtime, node *hierarchy.Node, selector string) go
|
||||
if childNode == nil {
|
||||
return goja.Undefined()
|
||||
}
|
||||
return nodeObject(runtime, childNode, selectorStringFromJS(arg))
|
||||
return nodeObject(runtime, childNode, selectorStringFromJS(runtime, arg))
|
||||
}
|
||||
childFindAll := func(call goja.FunctionCall) goja.Value {
|
||||
arg := call.Argument(0)
|
||||
childNodes := findAllNodesInSubtreeFromJS(runtime, node, arg)
|
||||
array := runtime.NewArray()
|
||||
for i, n := range childNodes {
|
||||
_ = array.Set(fmt.Sprintf("%d", i), nodeObject(runtime, n, selectorStringFromJS(arg)))
|
||||
_ = array.Set(fmt.Sprintf("%d", i), nodeObject(runtime, n, selectorStringFromJS(runtime, arg)))
|
||||
}
|
||||
return array
|
||||
}
|
||||
@@ -266,15 +267,62 @@ func selectorPathFromJS(runtime *goja.Runtime, arg goja.Value) ([]hierarchy.Sele
|
||||
|
||||
// selectorStringFromJS returns a string representation of the selector argument
|
||||
// for tagging returned element objects (used by selectorOf to reconstruct the
|
||||
// selector when the element is passed back as an action target).
|
||||
func selectorStringFromJS(arg goja.Value) string {
|
||||
if goja.IsUndefined(arg) || goja.IsNull(arg) {
|
||||
// selector when the element is passed back as an action target). Output
|
||||
// follows the canonical hierarchy selector grammar: "k:v" pairs space-joined
|
||||
// per object, chains joined by " > ".
|
||||
func selectorStringFromJS(runtime *goja.Runtime, arg goja.Value) string {
|
||||
if arg == nil || goja.IsUndefined(arg) || goja.IsNull(arg) {
|
||||
return ""
|
||||
}
|
||||
if s, ok := arg.Export().(string); ok {
|
||||
return s
|
||||
}
|
||||
return arg.String()
|
||||
exported := arg.Export()
|
||||
if slice, ok := exported.([]any); ok {
|
||||
object := arg.ToObject(runtime)
|
||||
if object == nil {
|
||||
return ""
|
||||
}
|
||||
parts := make([]string, 0, len(slice))
|
||||
for index := range slice {
|
||||
entry := object.Get(fmt.Sprintf("%d", index))
|
||||
if entry == nil || goja.IsUndefined(entry) || goja.IsNull(entry) {
|
||||
continue
|
||||
}
|
||||
segment := selectorObjectToString(runtime, entry)
|
||||
if segment == "" {
|
||||
continue
|
||||
}
|
||||
parts = append(parts, segment)
|
||||
}
|
||||
return strings.Join(parts, " > ")
|
||||
}
|
||||
return selectorObjectToString(runtime, arg)
|
||||
}
|
||||
|
||||
// selectorObjectToString formats a single JS object as a space-joined sequence
|
||||
// of "k:v" pairs, mirroring the hierarchy package's predicate grammar.
|
||||
func selectorObjectToString(runtime *goja.Runtime, arg goja.Value) string {
|
||||
if arg == nil || goja.IsUndefined(arg) || goja.IsNull(arg) {
|
||||
return ""
|
||||
}
|
||||
object := arg.ToObject(runtime)
|
||||
if object == nil {
|
||||
return ""
|
||||
}
|
||||
keys := object.Keys()
|
||||
parts := make([]string, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
if key == tagSelector {
|
||||
continue
|
||||
}
|
||||
value := object.Get(key)
|
||||
if value == nil || goja.IsUndefined(value) || goja.IsNull(value) {
|
||||
continue
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("%s:%s", key, value.String()))
|
||||
}
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
func lastActionObject(runtime *goja.Runtime, action *Action) goja.Value {
|
||||
|
||||
Reference in new issue
Block a user