...

Source file src/github.com/playwright-community/playwright-go/js_handle.go

Documentation: github.com/playwright-community/playwright-go

     1  package playwright
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"reflect"
     8  	"runtime/debug"
     9  	"strings"
    10  	"time"
    11  )
    12  
    13  type jsHandleImpl struct {
    14  	channelOwner
    15  	preview string
    16  }
    17  
    18  func (j *jsHandleImpl) Evaluate(expression string, options ...interface{}) (interface{}, error) {
    19  	var arg interface{}
    20  	forceExpression := false
    21  	if !isFunctionBody(expression) {
    22  		forceExpression = true
    23  	}
    24  	if len(options) == 1 {
    25  		arg = options[0]
    26  	} else if len(options) == 2 {
    27  		arg = options[0]
    28  		forceExpression = options[1].(bool)
    29  	}
    30  	result, err := j.channel.Send("evaluateExpression", map[string]interface{}{
    31  		"expression": expression,
    32  		"isFunction": !forceExpression,
    33  		"arg":        serializeArgument(arg),
    34  	})
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return parseResult(result), nil
    39  }
    40  
    41  func (j *jsHandleImpl) EvaluateHandle(expression string, options ...interface{}) (JSHandle, error) {
    42  	var arg interface{}
    43  	forceExpression := false
    44  	if !isFunctionBody(expression) {
    45  		forceExpression = true
    46  	}
    47  	if len(options) == 1 {
    48  		arg = options[0]
    49  	} else if len(options) == 2 {
    50  		arg = options[0]
    51  		forceExpression = options[1].(bool)
    52  	}
    53  	result, err := j.channel.Send("evaluateExpressionHandle", map[string]interface{}{
    54  		"expression": expression,
    55  		"isFunction": !forceExpression,
    56  		"arg":        serializeArgument(arg),
    57  	})
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	channelOwner := fromChannel(result)
    62  	if channelOwner == nil {
    63  		return nil, nil
    64  	}
    65  	return channelOwner.(*jsHandleImpl), nil
    66  }
    67  
    68  func (j *jsHandleImpl) GetProperty(name string) (JSHandle, error) {
    69  	channel, err := j.channel.Send("getProperty", map[string]interface{}{
    70  		"name": name,
    71  	})
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	return fromChannel(channel).(*jsHandleImpl), nil
    76  }
    77  
    78  func (j *jsHandleImpl) GetProperties() (map[string]JSHandle, error) {
    79  	properties, err := j.channel.Send("getPropertyList")
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	propertiesMap := make(map[string]JSHandle)
    84  	for _, property := range properties.([]interface{}) {
    85  		item := property.(map[string]interface{})
    86  		propertiesMap[item["name"].(string)] = fromChannel(item["value"]).(*jsHandleImpl)
    87  	}
    88  	return propertiesMap, nil
    89  }
    90  
    91  func (j *jsHandleImpl) AsElement() ElementHandle {
    92  	return nil
    93  }
    94  
    95  func (j *jsHandleImpl) Dispose() error {
    96  	_, err := j.channel.Send("dispose")
    97  	return err
    98  }
    99  
   100  func (j *jsHandleImpl) String() string {
   101  	return j.preview
   102  }
   103  
   104  func (j *jsHandleImpl) JSONValue() (interface{}, error) {
   105  	v, err := j.channel.Send("jsonValue")
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	return parseResult(v), nil
   110  }
   111  
   112  func parseValue(result interface{}) interface{} {
   113  	vMap := result.(map[string]interface{})
   114  	if v, ok := vMap["n"]; ok {
   115  		if math.Ceil(v.(float64))-v.(float64) == 0 {
   116  			return int(v.(float64))
   117  		}
   118  		return v.(float64)
   119  	}
   120  	if v, ok := vMap["s"]; ok {
   121  		return v.(string)
   122  	}
   123  	if v, ok := vMap["b"]; ok {
   124  		return v.(bool)
   125  	}
   126  	if v, ok := vMap["v"]; ok {
   127  		if v == "undefined" || v == "null" {
   128  			return nil
   129  		}
   130  		if v == "NaN" {
   131  			return math.NaN()
   132  		}
   133  		if v == "Infinity" {
   134  			return math.Inf(1)
   135  		}
   136  		if v == "-Infinity" {
   137  			return math.Inf(-1)
   138  		}
   139  		if v == "-0" {
   140  			return -0
   141  		}
   142  	}
   143  	if v, ok := vMap["d"]; ok {
   144  		t, _ := time.Parse(time.RFC3339, v.(string))
   145  		return t
   146  	}
   147  	if v, ok := vMap["a"]; ok {
   148  		aV := v.([]interface{})
   149  		for i := range aV {
   150  			aV[i] = parseValue(aV[i])
   151  		}
   152  		return aV
   153  	}
   154  	if v, ok := vMap["o"]; ok {
   155  		aV := v.([]interface{})
   156  		out := map[string]interface{}{}
   157  		for key := range aV {
   158  			entry := aV[key].(map[string]interface{})
   159  			out[entry["k"].(string)] = parseValue(entry["v"])
   160  		}
   161  		return out
   162  	}
   163  	panic(fmt.Errorf("Unexpected value: %v", vMap))
   164  }
   165  
   166  func serializeValue(value interface{}, handles *[]*channel, depth int) interface{} {
   167  	if handle, ok := value.(*elementHandleImpl); ok {
   168  		h := len(*handles)
   169  		*handles = append(*handles, handle.channel)
   170  		return map[string]interface{}{
   171  			"h": h,
   172  		}
   173  	}
   174  	if handle, ok := value.(*jsHandleImpl); ok {
   175  		h := len(*handles)
   176  		*handles = append(*handles, handle.channel)
   177  		return map[string]interface{}{
   178  			"h": h,
   179  		}
   180  	}
   181  	if depth > 100 {
   182  		panic(errors.New("Maximum argument depth exceeded"))
   183  	}
   184  	if value == nil {
   185  		return map[string]interface{}{
   186  			"v": "undefined",
   187  		}
   188  	}
   189  	refV := reflect.ValueOf(value)
   190  	if refV.Kind() == reflect.Float32 || refV.Kind() == reflect.Float64 {
   191  		floatV := refV.Float()
   192  		if math.IsInf(floatV, 1) {
   193  			return map[string]interface{}{
   194  				"v": "Infinity",
   195  			}
   196  		}
   197  		if math.IsInf(floatV, -1) {
   198  			return map[string]interface{}{
   199  				"v": "-Infinity",
   200  			}
   201  		}
   202  		if floatV == -0 {
   203  			return map[string]interface{}{
   204  				"v": "-0",
   205  			}
   206  		}
   207  		if math.IsNaN(floatV) {
   208  			return map[string]interface{}{
   209  				"v": "NaN",
   210  			}
   211  		}
   212  	}
   213  	if refV.Kind() == reflect.Slice {
   214  		aV := value.([]interface{})
   215  		for i := range aV {
   216  			aV[i] = serializeValue(aV[i], handles, depth+1)
   217  		}
   218  		return aV
   219  	}
   220  	if refV.Kind() == reflect.Map {
   221  		out := []interface{}{}
   222  		vM := value.(map[string]interface{})
   223  		for key := range vM {
   224  			out = append(out, map[string]interface{}{
   225  				"k": key,
   226  				"v": serializeValue(vM[key], handles, depth+1),
   227  			})
   228  		}
   229  		return map[string]interface{}{
   230  			"o": out,
   231  		}
   232  	}
   233  	switch v := value.(type) {
   234  	case time.Time:
   235  		return map[string]interface{}{
   236  			"d": v.Format(time.RFC3339) + "Z",
   237  		}
   238  	case int:
   239  		return map[string]interface{}{
   240  			"n": v,
   241  		}
   242  	case string:
   243  		return map[string]interface{}{
   244  			"s": v,
   245  		}
   246  	case bool:
   247  		return map[string]interface{}{
   248  			"b": v,
   249  		}
   250  	}
   251  	return map[string]interface{}{
   252  		"v": "undefined",
   253  	}
   254  }
   255  
   256  func parseResult(result interface{}) interface{} {
   257  	return parseValue(result)
   258  }
   259  
   260  func serializeArgument(arg interface{}) interface{} {
   261  	handles := []*channel{}
   262  	value := serializeValue(arg, &handles, 0)
   263  	return map[string]interface{}{
   264  		"value":   value,
   265  		"handles": handles,
   266  	}
   267  }
   268  
   269  func serializeError(err error) map[string]interface{} {
   270  	stack := strings.Split(string(debug.Stack()), "\n")
   271  	return map[string]interface{}{
   272  		"error": &errorPayload{
   273  			Name:    "Playwright for Go Error",
   274  			Message: err.Error(),
   275  			Stack:   strings.Join(stack[:len(stack)-5], "\n"),
   276  		},
   277  	}
   278  }
   279  
   280  func newJSHandle(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *jsHandleImpl {
   281  	bt := &jsHandleImpl{
   282  		preview: initializer["preview"].(string),
   283  	}
   284  	bt.createChannelOwner(bt, parent, objectType, guid, initializer)
   285  	bt.channel.On("previewUpdated", func(ev map[string]interface{}) {
   286  		bt.preview = ev["preview"].(string)
   287  	})
   288  	return bt
   289  }
   290  

View as plain text