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