mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
feat(verifier): fail the spec on a selector key that cannot match
An empty match is indistinguishable from a screen with no such element, so a mistyped key generates no action for the whole run and the campaign finishes clean having explored nothing. The goja boundary now throws, naming the key and the accepted list.
This commit is contained in:
1 parent
35b0856e6c
commit
1332471b72
3 files changed
+120
No files matched your search
@@ -3,6 +3,7 @@ package verifier
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -151,12 +152,14 @@ func findNodeFromJS(runtime *goja.Runtime, tree *hierarchy.Tree, arg goja.Value)
|
||||
return tree.FindNode(s)
|
||||
}
|
||||
if path, ok := selectorPathFromJS(runtime, arg); ok {
|
||||
requireKnownSelectorKeys(runtime, tree, path...)
|
||||
return tree.FindBySelectorPath(path)
|
||||
}
|
||||
sel := selectorFromJSObject(runtime, arg)
|
||||
if len(sel.Filters) == 0 {
|
||||
return nil
|
||||
}
|
||||
requireKnownSelectorKeys(runtime, tree, sel)
|
||||
return tree.Root.FindBySelector(sel)
|
||||
}
|
||||
|
||||
@@ -169,12 +172,14 @@ func findAllNodesFromJS(runtime *goja.Runtime, tree *hierarchy.Tree, arg goja.Va
|
||||
return tree.FindAllNodes(s)
|
||||
}
|
||||
if path, ok := selectorPathFromJS(runtime, arg); ok {
|
||||
requireKnownSelectorKeys(runtime, tree, path...)
|
||||
return tree.FindAllBySelectorPath(path)
|
||||
}
|
||||
sel := selectorFromJSObject(runtime, arg)
|
||||
if len(sel.Filters) == 0 {
|
||||
return nil
|
||||
}
|
||||
requireKnownSelectorKeys(runtime, tree, sel)
|
||||
return tree.Root.FindAllBySelector(sel)
|
||||
}
|
||||
|
||||
@@ -187,12 +192,14 @@ func findNodeInSubtreeFromJS(runtime *goja.Runtime, node *hierarchy.Node, arg go
|
||||
return node.Find(s)
|
||||
}
|
||||
if path, ok := selectorPathFromJS(runtime, arg); ok {
|
||||
requireKnownSelectorKeys(runtime, node.Tree(), path...)
|
||||
return node.FindBySelectorPath(path)
|
||||
}
|
||||
sel := selectorFromJSObject(runtime, arg)
|
||||
if len(sel.Filters) == 0 {
|
||||
return nil
|
||||
}
|
||||
requireKnownSelectorKeys(runtime, node.Tree(), sel)
|
||||
return node.FindBySelector(sel)
|
||||
}
|
||||
|
||||
@@ -205,15 +212,41 @@ func findAllNodesInSubtreeFromJS(runtime *goja.Runtime, node *hierarchy.Node, ar
|
||||
return node.FindAll(s)
|
||||
}
|
||||
if path, ok := selectorPathFromJS(runtime, arg); ok {
|
||||
requireKnownSelectorKeys(runtime, node.Tree(), path...)
|
||||
return node.FindAllBySelectorPath(path)
|
||||
}
|
||||
sel := selectorFromJSObject(runtime, arg)
|
||||
if len(sel.Filters) == 0 {
|
||||
return nil
|
||||
}
|
||||
requireKnownSelectorKeys(runtime, node.Tree(), sel)
|
||||
return node.FindAllBySelector(sel)
|
||||
}
|
||||
|
||||
// requireKnownSelectorKeys throws a JS error when a selector names a key that
|
||||
// can never match. Returning an empty result instead is indistinguishable from
|
||||
// a screen that simply has no such element, so a spec built on a mistyped key
|
||||
// generates no action, the runner waits out every step, and the campaign
|
||||
// finishes clean having explored nothing.
|
||||
func requireKnownSelectorKeys(
|
||||
runtime *goja.Runtime,
|
||||
tree *hierarchy.Tree,
|
||||
selectors ...hierarchy.Selector,
|
||||
) {
|
||||
var unknown []string
|
||||
for _, sel := range selectors {
|
||||
for _, key := range tree.UnknownSelectorKeys(sel) {
|
||||
if !slices.Contains(unknown, key) {
|
||||
unknown = append(unknown, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(unknown) == 0 {
|
||||
return
|
||||
}
|
||||
panic(runtime.NewTypeError(hierarchy.UnknownSelectorKeyMessage(unknown)))
|
||||
}
|
||||
|
||||
// selectorFromJSObject converts a JS object {attr: value, ...} into a Selector.
|
||||
func selectorFromJSObject(runtime *goja.Runtime, arg goja.Value) hierarchy.Selector {
|
||||
obj := arg.ToObject(runtime)
|
||||
|
||||
Reference in new issue
Block a user