mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
feat(verifier): wire hierarchy into state.ax and carry element coords in Action
This commit is contained in:
1 parent
e539e89438
commit
5f2a2d52ab
4 files changed
+105
-24
No files matched your search
@@ -5,14 +5,17 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
|
||||
"github.com/priyanshujain/uatu/internal/hierarchy"
|
||||
)
|
||||
|
||||
// Snapshots is the per-step extractor output forwarded by the SDK.
|
||||
type Snapshots map[string]json.RawMessage
|
||||
|
||||
// stateObject builds a JS-side `{ snapshots, ax }` matching the State type
|
||||
// from pkg/spec-api. ax is currently a stub returning nothing.
|
||||
func stateObject(runtime *goja.Runtime, snapshots Snapshots) (*goja.Object, error) {
|
||||
// from pkg/spec-api. ax is backed by the parsed uiautomator hierarchy when
|
||||
// one is provided.
|
||||
func stateObject(runtime *goja.Runtime, snapshots Snapshots, tree *hierarchy.Tree) (*goja.Object, error) {
|
||||
state := runtime.NewObject()
|
||||
snapshotsObject := runtime.NewObject()
|
||||
for key, raw := range snapshots {
|
||||
@@ -27,20 +30,59 @@ func stateObject(runtime *goja.Runtime, snapshots Snapshots) (*goja.Object, erro
|
||||
if err := state.Set("snapshots", snapshotsObject); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessibility := runtime.NewObject()
|
||||
if err := accessibility.Set("find", runtime.ToValue(func(string) goja.Value { return goja.Undefined() })); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := accessibility.Set("findAll", runtime.ToValue(func(string) []goja.Value { return nil })); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := state.Set("ax", accessibility); err != nil {
|
||||
if err := state.Set("ax", accessibilityObject(runtime, tree)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func accessibilityObject(runtime *goja.Runtime, tree *hierarchy.Tree) *goja.Object {
|
||||
accessibility := runtime.NewObject()
|
||||
find := func(selector string) goja.Value {
|
||||
if tree == nil {
|
||||
return goja.Undefined()
|
||||
}
|
||||
element := tree.Find(selector)
|
||||
if element == nil {
|
||||
return goja.Undefined()
|
||||
}
|
||||
return elementObject(runtime, element, selector)
|
||||
}
|
||||
findAll := func(selector string) []goja.Value {
|
||||
if tree == nil {
|
||||
return nil
|
||||
}
|
||||
elements := tree.FindAll(selector)
|
||||
result := make([]goja.Value, len(elements))
|
||||
for index, element := range elements {
|
||||
result[index] = elementObject(runtime, element, selector)
|
||||
}
|
||||
return result
|
||||
}
|
||||
_ = accessibility.Set("find", runtime.ToValue(find))
|
||||
_ = accessibility.Set("findAll", runtime.ToValue(findAll))
|
||||
return accessibility
|
||||
}
|
||||
|
||||
func elementObject(runtime *goja.Runtime, element *hierarchy.Element, selector string) goja.Value {
|
||||
object := runtime.NewObject()
|
||||
centerX, centerY := element.Bounds.Center()
|
||||
_ = object.Set("id", element.ResourceID)
|
||||
_ = object.Set("text", element.Text)
|
||||
_ = object.Set("desc", element.Description)
|
||||
_ = object.Set("class", element.Class)
|
||||
_ = object.Set("x", centerX)
|
||||
_ = object.Set("y", centerY)
|
||||
_ = object.Set(tagSelector, selector)
|
||||
bounds := runtime.NewObject()
|
||||
_ = bounds.Set("left", element.Bounds.Left)
|
||||
_ = bounds.Set("top", element.Bounds.Top)
|
||||
_ = bounds.Set("right", element.Bounds.Right)
|
||||
_ = bounds.Set("bottom", element.Bounds.Bottom)
|
||||
_ = object.Set("bounds", bounds)
|
||||
return object
|
||||
}
|
||||
|
||||
func jsonToJSValue(runtime *goja.Runtime, raw json.RawMessage) (goja.Value, error) {
|
||||
if len(raw) == 0 {
|
||||
return goja.Undefined(), nil
|
||||
@@ -66,16 +108,48 @@ func jsValueToAction(runtime *goja.Runtime, value goja.Value) (Action, error) {
|
||||
switch kind {
|
||||
case "Tap":
|
||||
on := object.Get("on")
|
||||
return Action{Kind: ActionKindTap, On: stringOf(on)}, nil
|
||||
x, y := coordinatesOf(runtime, on)
|
||||
return Action{Kind: ActionKindTap, On: selectorOf(runtime, on), X: x, Y: y}, nil
|
||||
case "InputText":
|
||||
into := object.Get("into")
|
||||
text := object.Get("text")
|
||||
return Action{Kind: ActionKindInputText, On: stringOf(into), Text: stringOf(text)}, nil
|
||||
x, y := coordinatesOf(runtime, into)
|
||||
return Action{Kind: ActionKindInputText, On: selectorOf(runtime, into), Text: stringOf(text), X: x, Y: y}, nil
|
||||
default:
|
||||
return Action{}, fmt.Errorf("unknown action kind %q", kind)
|
||||
}
|
||||
}
|
||||
|
||||
func selectorOf(runtime *goja.Runtime, value goja.Value) string {
|
||||
if value == nil || goja.IsNull(value) || goja.IsUndefined(value) {
|
||||
return ""
|
||||
}
|
||||
object := value.ToObject(runtime)
|
||||
if object == nil {
|
||||
return value.String()
|
||||
}
|
||||
if tag := object.Get(tagSelector); tag != nil && !goja.IsUndefined(tag) {
|
||||
return tag.String()
|
||||
}
|
||||
return value.String()
|
||||
}
|
||||
|
||||
func coordinatesOf(runtime *goja.Runtime, value goja.Value) (int, int) {
|
||||
if value == nil || goja.IsNull(value) || goja.IsUndefined(value) {
|
||||
return 0, 0
|
||||
}
|
||||
object := value.ToObject(runtime)
|
||||
if object == nil {
|
||||
return 0, 0
|
||||
}
|
||||
xValue := object.Get("x")
|
||||
yValue := object.Get("y")
|
||||
if xValue == nil || yValue == nil || goja.IsUndefined(xValue) || goja.IsUndefined(yValue) {
|
||||
return 0, 0
|
||||
}
|
||||
return int(xValue.ToInteger()), int(yValue.ToInteger())
|
||||
}
|
||||
|
||||
func stringOf(value goja.Value) string {
|
||||
if value == nil || goja.IsNull(value) || goja.IsUndefined(value) {
|
||||
return ""
|
||||
|
||||
Reference in new issue
Block a user