github.com/MontFerret/ferret@v0.18.0/pkg/drivers/cdp/eval/function_test.go (about) 1 package eval 2 3 import ( 4 "testing" 5 6 "github.com/mafredri/cdp/protocol/runtime" 7 . "github.com/smartystreets/goconvey/convey" 8 9 "github.com/MontFerret/ferret/pkg/drivers" 10 "github.com/MontFerret/ferret/pkg/runtime/values" 11 ) 12 13 func TestFunction(t *testing.T) { 14 Convey("Function", t, func() { 15 Convey(".AsAsync", func() { 16 Convey("Should set async=true", func() { 17 f := F("return 'foo'").AsAsync() 18 args := f.eval(EmptyExecutionContextID) 19 20 So(*args.AwaitPromise, ShouldBeTrue) 21 }) 22 }) 23 24 Convey(".AsSync", func() { 25 Convey("Should set async=false", func() { 26 f := F("return 'foo'").AsAsync() 27 args := f.eval(EmptyExecutionContextID) 28 29 So(*args.AwaitPromise, ShouldBeTrue) 30 31 args = f.AsSync().eval(EmptyExecutionContextID) 32 33 So(*args.AwaitPromise, ShouldBeFalse) 34 }) 35 }) 36 37 Convey(".AsNamed", func() { 38 Convey("When without args", func() { 39 Convey("Should generate a wrapper with a given function name", func() { 40 name := "getFoo" 41 exp := "return 'foo'" 42 f := F(exp).AsNamed(name) 43 44 So(f.name, ShouldEqual, name) 45 46 call := f.eval(EmptyExecutionContextID) 47 48 expected := "function " + name + "() {\n" + exp + "\n}" 49 50 So(call.FunctionDeclaration, ShouldEqual, expected) 51 }) 52 }) 53 54 Convey("When with args", func() { 55 Convey("When a declaration is an expression", func() { 56 Convey("Should generate a wrapper with a given function name", func() { 57 name := "getFoo" 58 exp := "return 'foo'" 59 f := F(exp). 60 AsNamed(name). 61 WithArg("bar"). 62 WithArg(1) 63 64 So(f.name, ShouldEqual, name) 65 66 call := f.eval(EmptyExecutionContextID) 67 68 expected := "function " + name + "(arg1,arg2) {\n" + exp + "\n}" 69 70 So(call.FunctionDeclaration, ShouldEqual, expected) 71 }) 72 }) 73 74 Convey("When a declaration is an arrow function", func() { 75 Convey("Should generate a wrapper with a given function name", func() { 76 name := "getValue" 77 exp := "(el) => el.value" 78 f := F(exp). 79 AsNamed(name). 80 WithArgRef("my_element"). 81 WithArg(1) 82 83 So(f.name, ShouldEqual, name) 84 85 call := f.eval(EmptyExecutionContextID) 86 87 expected := "function " + name + "() {\n" + 88 "const $exp = " + exp + ";\n" + 89 "return $exp.apply(this, arguments);\n" + 90 "}" 91 92 So(call.FunctionDeclaration, ShouldEqual, expected) 93 }) 94 }) 95 96 Convey("When a declaration is a plain function", func() { 97 Convey("Should generate a wrapper with a given function name", func() { 98 name := "getValue" 99 exp := "function getElementValue(el) => el.value" 100 f := F(exp). 101 AsNamed(name). 102 WithArgRef("my_element"). 103 WithArg(1) 104 105 So(f.name, ShouldEqual, name) 106 107 call := f.eval(EmptyExecutionContextID) 108 109 expected := "function " + name + "() {\n" + 110 "const $exp = " + exp + ";\n" + 111 "return $exp.apply(this, arguments);\n" + 112 "}" 113 114 So(call.FunctionDeclaration, ShouldEqual, expected) 115 }) 116 }) 117 }) 118 }) 119 120 Convey(".AsAnonymous", func() { 121 Convey("When without args", func() { 122 Convey("Should generate an anonymous wrapper", func() { 123 name := "" 124 exp := "return 'foo'" 125 f := F(exp).AsNamed("getFoo").AsAnonymous() 126 127 So(f.name, ShouldEqual, name) 128 129 call := f.eval(EmptyExecutionContextID) 130 131 expected := "function() {\n" + exp + "\n}" 132 133 So(call.FunctionDeclaration, ShouldEqual, expected) 134 }) 135 }) 136 137 Convey("When with args", func() { 138 Convey("When a declaration is an expression", func() { 139 Convey("Should generate an anonymous wrapper", func() { 140 name := "" 141 exp := "return 'foo'" 142 f := F(exp). 143 AsNamed("getFoo"). 144 AsAnonymous(). 145 WithArg("bar"). 146 WithArg(1) 147 148 So(f.name, ShouldEqual, name) 149 150 call := f.eval(EmptyExecutionContextID) 151 152 expected := "function(arg1,arg2) {\n" + exp + "\n}" 153 154 So(call.FunctionDeclaration, ShouldEqual, expected) 155 }) 156 }) 157 158 Convey("When a declaration is an arrow function", func() { 159 Convey("Should NOT generate a wrapper", func() { 160 name := "" 161 exp := "(el) => el.value" 162 f := F(exp). 163 AsNamed("getValue"). 164 AsAnonymous(). 165 WithArgRef("my_element"). 166 WithArg(1) 167 168 So(f.name, ShouldEqual, name) 169 170 call := f.eval(EmptyExecutionContextID) 171 172 So(call.FunctionDeclaration, ShouldEqual, exp) 173 }) 174 }) 175 176 Convey("When a declaration is a plain function", func() { 177 Convey("Should NOT generate a wrapper", func() { 178 name := "" 179 exp := "function(el) => el.value" 180 f := F(exp). 181 AsNamed("getValue"). 182 AsAnonymous(). 183 WithArgRef("my_element"). 184 WithArg(1) 185 186 So(f.name, ShouldEqual, name) 187 188 call := f.eval(EmptyExecutionContextID) 189 190 So(call.FunctionDeclaration, ShouldEqual, exp) 191 }) 192 }) 193 }) 194 }) 195 196 Convey(".CallOn", func() { 197 Convey("It should use a given ownerID over ContextID", func() { 198 ownerID := runtime.RemoteObjectID("foo") 199 contextID := runtime.ExecutionContextID(42) 200 201 f := F("return 'foo'").CallOn(ownerID) 202 call := f.eval(contextID) 203 204 So(call.ExecutionContextID, ShouldBeNil) 205 So(call.ObjectID, ShouldNotBeNil) 206 So(*call.ObjectID, ShouldEqual, ownerID) 207 }) 208 209 Convey("It should use a given ContextID when ownerID is empty or nil", func() { 210 ownerID := runtime.RemoteObjectID("") 211 contextID := runtime.ExecutionContextID(42) 212 213 f := F("return 'foo'").CallOn(ownerID) 214 call := f.eval(contextID) 215 216 So(call.ExecutionContextID, ShouldNotBeNil) 217 So(call.ObjectID, ShouldBeNil) 218 So(*call.ExecutionContextID, ShouldEqual, contextID) 219 }) 220 }) 221 222 Convey(".WithArgRef", func() { 223 Convey("Should add argument with a given RemoteObjectID", func() { 224 f := F("return 'foo'") 225 id1 := runtime.RemoteObjectID("foo") 226 id2 := runtime.RemoteObjectID("bar") 227 id3 := runtime.RemoteObjectID("baz") 228 229 f.WithArgRef(id1).WithArgRef(id2).WithArgRef(id3) 230 231 So(f.Length(), ShouldEqual, 3) 232 233 arg1 := f.args[0] 234 arg2 := f.args[1] 235 arg3 := f.args[2] 236 237 So(*arg1.ObjectID, ShouldEqual, id1) 238 So(arg1.Value, ShouldBeNil) 239 So(arg1.UnserializableValue, ShouldBeNil) 240 241 So(*arg2.ObjectID, ShouldEqual, id2) 242 So(arg2.Value, ShouldBeNil) 243 So(arg2.UnserializableValue, ShouldBeNil) 244 245 So(*arg3.ObjectID, ShouldEqual, id3) 246 So(arg3.Value, ShouldBeNil) 247 So(arg3.UnserializableValue, ShouldBeNil) 248 }) 249 }) 250 251 Convey(".WithArgValue", func() { 252 Convey("Should add argument with a given Value", func() { 253 f := F("return 'foo'") 254 val1 := values.NewString("foo") 255 val2 := values.NewInt(1) 256 val3 := values.NewBoolean(true) 257 258 f.WithArgValue(val1).WithArgValue(val2).WithArgValue(val3) 259 260 So(f.Length(), ShouldEqual, 3) 261 262 arg1 := f.args[0] 263 arg2 := f.args[1] 264 arg3 := f.args[2] 265 266 So(arg1.ObjectID, ShouldBeNil) 267 So(arg1.Value, ShouldResemble, values.MustMarshal(val1)) 268 So(arg1.UnserializableValue, ShouldBeNil) 269 270 So(arg2.ObjectID, ShouldBeNil) 271 So(arg2.Value, ShouldResemble, values.MustMarshal(val2)) 272 So(arg2.UnserializableValue, ShouldBeNil) 273 274 So(arg3.ObjectID, ShouldBeNil) 275 So(arg3.Value, ShouldResemble, values.MustMarshal(val3)) 276 So(arg3.UnserializableValue, ShouldBeNil) 277 }) 278 }) 279 280 Convey(".WithArg", func() { 281 Convey("Should add argument with a given any type", func() { 282 f := F("return 'foo'") 283 val1 := "foo" 284 val2 := 1 285 val3 := true 286 287 f.WithArg(val1).WithArg(val2).WithArg(val3) 288 289 So(f.Length(), ShouldEqual, 3) 290 291 arg1 := f.args[0] 292 arg2 := f.args[1] 293 arg3 := f.args[2] 294 295 So(arg1.ObjectID, ShouldBeNil) 296 So(arg1.Value, ShouldResemble, values.MustMarshalAny(val1)) 297 So(arg1.UnserializableValue, ShouldBeNil) 298 299 So(arg2.ObjectID, ShouldBeNil) 300 So(arg2.Value, ShouldResemble, values.MustMarshalAny(val2)) 301 So(arg2.UnserializableValue, ShouldBeNil) 302 303 So(arg3.ObjectID, ShouldBeNil) 304 So(arg3.Value, ShouldResemble, values.MustMarshalAny(val3)) 305 So(arg3.UnserializableValue, ShouldBeNil) 306 }) 307 }) 308 309 Convey(".WithArgSelector", func() { 310 Convey("Should add argument with a given QuerySelector", func() { 311 f := F("return 'foo'") 312 val1 := drivers.NewCSSSelector(".foo-bar") 313 val2 := drivers.NewCSSSelector("#submit") 314 val3 := drivers.NewXPathSelector("//*[@id='q']") 315 316 f.WithArgSelector(val1).WithArgSelector(val2).WithArgSelector(val3) 317 318 So(f.Length(), ShouldEqual, 3) 319 320 arg1 := f.args[0] 321 arg2 := f.args[1] 322 arg3 := f.args[2] 323 324 So(arg1.ObjectID, ShouldBeNil) 325 So(arg1.Value, ShouldResemble, values.MustMarshalAny(val1.String())) 326 So(arg1.UnserializableValue, ShouldBeNil) 327 328 So(arg2.ObjectID, ShouldBeNil) 329 So(arg2.Value, ShouldResemble, values.MustMarshalAny(val2.String())) 330 So(arg2.UnserializableValue, ShouldBeNil) 331 332 So(arg3.ObjectID, ShouldBeNil) 333 So(arg3.Value, ShouldResemble, values.MustMarshalAny(val3.String())) 334 So(arg3.UnserializableValue, ShouldBeNil) 335 }) 336 }) 337 338 Convey(".String", func() { 339 Convey("It should return a function expression", func() { 340 exp := "return 'foo'" 341 f := F(exp) 342 343 So(f.String(), ShouldEqual, exp) 344 }) 345 }) 346 347 Convey(".returnNothing", func() { 348 Convey("It should set return by value to false", func() { 349 f := F("return 'foo'").returnNothing() 350 call := f.eval(EmptyExecutionContextID) 351 352 So(*call.ReturnByValue, ShouldBeFalse) 353 }) 354 }) 355 356 Convey(".returnValue", func() { 357 Convey("It should set return by value to true", func() { 358 f := F("return 'foo'").returnValue() 359 call := f.eval(EmptyExecutionContextID) 360 361 So(*call.ReturnByValue, ShouldBeTrue) 362 }) 363 }) 364 365 Convey(".returnRef", func() { 366 Convey("It should set return by value to false", func() { 367 f := F("return 'foo'").returnValue() 368 call := f.eval(EmptyExecutionContextID) 369 370 So(*call.ReturnByValue, ShouldBeTrue) 371 372 f.returnRef() 373 374 call = f.eval(EmptyExecutionContextID) 375 376 So(*call.ReturnByValue, ShouldBeFalse) 377 }) 378 }) 379 380 Convey(".compile", func() { 381 Convey("When Anonymous", func() { 382 Convey("When without args", func() { 383 Convey("Should generate an expression", func() { 384 name := "" 385 exp := "return 'foo'" 386 f := F(exp) 387 388 So(f.name, ShouldEqual, name) 389 390 call := f.compile(EmptyExecutionContextID) 391 392 expected := "const args = [];\n" + 393 "const " + compiledExpName + " = function() {\n" + exp + "\n};\n" + 394 compiledExpName + ".apply(this, args);\n" 395 396 So(call.Expression, ShouldEqual, expected) 397 }) 398 399 Convey("When a function is given", func() { 400 Convey("Should generate an expression", func() { 401 name := "" 402 exp := "() => return 'foo'" 403 f := F(exp) 404 405 So(f.name, ShouldEqual, name) 406 407 call := f.compile(EmptyExecutionContextID) 408 409 expected := "const args = [];\n" + 410 "const " + compiledExpName + " = " + exp + ";\n" + 411 compiledExpName + ".apply(this, args);\n" 412 413 So(call.Expression, ShouldEqual, expected) 414 }) 415 }) 416 }) 417 418 Convey("When with args", func() { 419 Convey("Should generate an expression", func() { 420 name := "" 421 exp := "return 'foo'" 422 f := F(exp).WithArg(1).WithArg("test").WithArg([]int{1, 2}) 423 424 So(f.name, ShouldEqual, name) 425 426 call := f.compile(EmptyExecutionContextID) 427 428 expected := "const args = [\n" + 429 "1,\n" + 430 "\"test\",\n" + 431 "[1,2],\n" + 432 "];\n" + 433 "const " + compiledExpName + " = function(arg1,arg2,arg3) {\n" + exp + "\n};\n" + 434 compiledExpName + ".apply(this, args);\n" 435 436 So(call.Expression, ShouldEqual, expected) 437 }) 438 439 Convey("When a function is given", func() { 440 Convey("Should generate an expression", func() { 441 name := "" 442 exp := "() => return 'foo'" 443 f := F(exp).WithArg(1).WithArg("test").WithArg([]int{1, 2}) 444 445 So(f.name, ShouldEqual, name) 446 447 call := f.compile(EmptyExecutionContextID) 448 449 expected := "const args = [\n" + 450 "1,\n" + 451 "\"test\",\n" + 452 "[1,2],\n" + 453 "];\n" + 454 "const " + compiledExpName + " = " + exp + ";\n" + 455 compiledExpName + ".apply(this, args);\n" 456 457 So(call.Expression, ShouldEqual, expected) 458 }) 459 }) 460 }) 461 }) 462 }) 463 }) 464 }