github.com/MontFerret/ferret@v0.18.0/pkg/drivers/cdp/dom/element.go (about) 1 package dom 2 3 import ( 4 "context" 5 "hash/fnv" 6 "strings" 7 "time" 8 9 "github.com/mafredri/cdp" 10 "github.com/mafredri/cdp/protocol/runtime" 11 "github.com/pkg/errors" 12 "github.com/rs/zerolog" 13 "github.com/wI2L/jettison" 14 15 "github.com/MontFerret/ferret/pkg/drivers" 16 "github.com/MontFerret/ferret/pkg/drivers/cdp/eval" 17 "github.com/MontFerret/ferret/pkg/drivers/cdp/events" 18 "github.com/MontFerret/ferret/pkg/drivers/cdp/input" 19 "github.com/MontFerret/ferret/pkg/drivers/cdp/templates" 20 "github.com/MontFerret/ferret/pkg/drivers/common" 21 "github.com/MontFerret/ferret/pkg/runtime/core" 22 "github.com/MontFerret/ferret/pkg/runtime/logging" 23 "github.com/MontFerret/ferret/pkg/runtime/values" 24 ) 25 26 type HTMLElement struct { 27 logger zerolog.Logger 28 client *cdp.Client 29 dom *Manager 30 input *input.Manager 31 eval *eval.Runtime 32 id runtime.RemoteObjectID 33 nodeType *common.LazyValue 34 nodeName *common.LazyValue 35 } 36 37 func NewHTMLElement( 38 logger zerolog.Logger, 39 client *cdp.Client, 40 domManager *Manager, 41 input *input.Manager, 42 exec *eval.Runtime, 43 id runtime.RemoteObjectID, 44 ) *HTMLElement { 45 el := new(HTMLElement) 46 el.logger = logging. 47 WithName(logger.With(), "dom_element"). 48 Str("object_id", string(id)). 49 Logger() 50 el.client = client 51 el.dom = domManager 52 el.input = input 53 el.eval = exec 54 el.id = id 55 el.nodeType = common.NewLazyValue(func(ctx context.Context) (core.Value, error) { 56 return el.eval.EvalValue(ctx, templates.GetNodeType(el.id)) 57 }) 58 el.nodeName = common.NewLazyValue(func(ctx context.Context) (core.Value, error) { 59 return el.eval.EvalValue(ctx, templates.GetNodeName(el.id)) 60 }) 61 62 return el 63 } 64 65 func (el *HTMLElement) RemoteID() runtime.RemoteObjectID { 66 return el.id 67 } 68 69 func (el *HTMLElement) Close() error { 70 return nil 71 } 72 73 func (el *HTMLElement) Type() core.Type { 74 return drivers.HTMLElementType 75 } 76 77 func (el *HTMLElement) MarshalJSON() ([]byte, error) { 78 return jettison.MarshalOpts(el.String(), jettison.NoHTMLEscaping()) 79 } 80 81 func (el *HTMLElement) String() string { 82 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(drivers.DefaultWaitTimeout)*time.Millisecond) 83 defer cancel() 84 85 res, err := el.GetInnerHTML(ctx) 86 87 if err != nil { 88 el.logError(errors.Wrap(err, "HTMLElement.String")) 89 90 return "" 91 } 92 93 return res.String() 94 } 95 96 func (el *HTMLElement) Compare(other core.Value) int64 { 97 switch other.Type() { 98 case drivers.HTMLElementType: 99 other := other.(drivers.HTMLElement) 100 101 return int64(strings.Compare(el.String(), other.String())) 102 default: 103 return drivers.Compare(el.Type(), other.Type()) 104 } 105 } 106 107 func (el *HTMLElement) Unwrap() interface{} { 108 return el 109 } 110 111 func (el *HTMLElement) Hash() uint64 { 112 h := fnv.New64a() 113 114 h.Write([]byte(el.Type().String())) 115 h.Write([]byte(":")) 116 h.Write([]byte(el.id)) 117 118 return h.Sum64() 119 } 120 121 func (el *HTMLElement) Copy() core.Value { 122 return values.None 123 } 124 125 func (el *HTMLElement) Iterate(_ context.Context) (core.Iterator, error) { 126 return common.NewIterator(el) 127 } 128 129 func (el *HTMLElement) GetIn(ctx context.Context, path []core.Value) (core.Value, core.PathError) { 130 return common.GetInElement(ctx, path, el) 131 } 132 133 func (el *HTMLElement) SetIn(ctx context.Context, path []core.Value, value core.Value) core.PathError { 134 return common.SetInElement(ctx, path, el, value) 135 } 136 137 func (el *HTMLElement) GetValue(ctx context.Context) (core.Value, error) { 138 return el.eval.EvalValue(ctx, templates.GetValue(el.id)) 139 } 140 141 func (el *HTMLElement) SetValue(ctx context.Context, value core.Value) error { 142 return el.eval.Eval(ctx, templates.SetValue(el.id, value)) 143 } 144 145 func (el *HTMLElement) GetNodeType(ctx context.Context) (values.Int, error) { 146 out, err := el.nodeType.Read(ctx) 147 148 if err != nil { 149 return values.ZeroInt, err 150 } 151 152 return values.ToInt(out), nil 153 } 154 155 func (el *HTMLElement) GetNodeName(ctx context.Context) (values.String, error) { 156 out, err := el.nodeName.Read(ctx) 157 158 if err != nil { 159 return values.EmptyString, err 160 } 161 162 return values.ToString(out), nil 163 } 164 165 func (el *HTMLElement) Length() values.Int { 166 value, err := el.eval.EvalValue(context.Background(), templates.GetChildrenCount(el.id)) 167 168 if err != nil { 169 el.logError(err) 170 171 return 0 172 } 173 174 return values.ToInt(value) 175 } 176 177 func (el *HTMLElement) GetStyles(ctx context.Context) (*values.Object, error) { 178 out, err := el.eval.EvalValue(ctx, templates.GetStyles(el.id)) 179 180 if err != nil { 181 return values.NewObject(), err 182 } 183 184 return values.ToObject(ctx, out), nil 185 } 186 187 func (el *HTMLElement) GetStyle(ctx context.Context, name values.String) (core.Value, error) { 188 return el.eval.EvalValue(ctx, templates.GetStyle(el.id, name)) 189 } 190 191 func (el *HTMLElement) SetStyles(ctx context.Context, styles *values.Object) error { 192 return el.eval.Eval(ctx, templates.SetStyles(el.id, styles)) 193 } 194 195 func (el *HTMLElement) SetStyle(ctx context.Context, name, value values.String) error { 196 return el.eval.Eval(ctx, templates.SetStyle(el.id, name, value)) 197 } 198 199 func (el *HTMLElement) RemoveStyle(ctx context.Context, names ...values.String) error { 200 return el.eval.Eval(ctx, templates.RemoveStyles(el.id, names)) 201 } 202 203 func (el *HTMLElement) GetAttributes(ctx context.Context) (*values.Object, error) { 204 out, err := el.eval.EvalValue(ctx, templates.GetAttributes(el.id)) 205 206 if err != nil { 207 return values.NewObject(), err 208 } 209 210 return values.ToObject(ctx, out), nil 211 } 212 213 func (el *HTMLElement) GetAttribute(ctx context.Context, name values.String) (core.Value, error) { 214 return el.eval.EvalValue(ctx, templates.GetAttribute(el.id, name)) 215 } 216 217 func (el *HTMLElement) SetAttributes(ctx context.Context, attrs *values.Object) error { 218 return el.eval.Eval(ctx, templates.SetAttributes(el.id, attrs)) 219 } 220 221 func (el *HTMLElement) SetAttribute(ctx context.Context, name, value values.String) error { 222 return el.eval.Eval(ctx, templates.SetAttribute(el.id, name, value)) 223 } 224 225 func (el *HTMLElement) RemoveAttribute(ctx context.Context, names ...values.String) error { 226 return el.eval.Eval(ctx, templates.RemoveAttributes(el.id, names)) 227 } 228 229 func (el *HTMLElement) GetChildNodes(ctx context.Context) (*values.Array, error) { 230 return el.eval.EvalElements(ctx, templates.GetChildren(el.id)) 231 } 232 233 func (el *HTMLElement) GetChildNode(ctx context.Context, idx values.Int) (core.Value, error) { 234 return el.eval.EvalElement(ctx, templates.GetChildByIndex(el.id, idx)) 235 } 236 237 func (el *HTMLElement) GetParentElement(ctx context.Context) (core.Value, error) { 238 return el.eval.EvalElement(ctx, templates.GetParent(el.id)) 239 } 240 241 func (el *HTMLElement) GetPreviousElementSibling(ctx context.Context) (core.Value, error) { 242 return el.eval.EvalElement(ctx, templates.GetPreviousElementSibling(el.id)) 243 } 244 245 func (el *HTMLElement) GetNextElementSibling(ctx context.Context) (core.Value, error) { 246 return el.eval.EvalElement(ctx, templates.GetNextElementSibling(el.id)) 247 } 248 249 func (el *HTMLElement) QuerySelector(ctx context.Context, selector drivers.QuerySelector) (core.Value, error) { 250 return el.eval.EvalElement(ctx, templates.QuerySelector(el.id, selector)) 251 } 252 253 func (el *HTMLElement) QuerySelectorAll(ctx context.Context, selector drivers.QuerySelector) (*values.Array, error) { 254 return el.eval.EvalElements(ctx, templates.QuerySelectorAll(el.id, selector)) 255 } 256 257 func (el *HTMLElement) XPath(ctx context.Context, expression values.String) (result core.Value, err error) { 258 return el.eval.EvalValue(ctx, templates.XPath(el.id, expression)) 259 } 260 261 func (el *HTMLElement) GetInnerText(ctx context.Context) (values.String, error) { 262 out, err := el.eval.EvalValue(ctx, templates.GetInnerText(el.id)) 263 264 if err != nil { 265 return values.EmptyString, err 266 } 267 268 return values.ToString(out), nil 269 } 270 271 func (el *HTMLElement) SetInnerText(ctx context.Context, innerText values.String) error { 272 return el.eval.Eval( 273 ctx, 274 templates.SetInnerText(el.id, innerText), 275 ) 276 } 277 278 func (el *HTMLElement) GetInnerTextBySelector(ctx context.Context, selector drivers.QuerySelector) (values.String, error) { 279 out, err := el.eval.EvalValue(ctx, templates.GetInnerTextBySelector(el.id, selector)) 280 281 if err != nil { 282 return values.EmptyString, err 283 } 284 285 return values.ToString(out), nil 286 } 287 288 func (el *HTMLElement) SetInnerTextBySelector(ctx context.Context, selector drivers.QuerySelector, innerText values.String) error { 289 return el.eval.Eval( 290 ctx, 291 templates.SetInnerTextBySelector(el.id, selector, innerText), 292 ) 293 } 294 295 func (el *HTMLElement) GetInnerTextBySelectorAll(ctx context.Context, selector drivers.QuerySelector) (*values.Array, error) { 296 out, err := el.eval.EvalValue(ctx, templates.GetInnerTextBySelectorAll(el.id, selector)) 297 298 if err != nil { 299 return values.EmptyArray(), err 300 } 301 302 return values.ToArray(ctx, out), nil 303 } 304 305 func (el *HTMLElement) GetInnerHTML(ctx context.Context) (values.String, error) { 306 out, err := el.eval.EvalValue(ctx, templates.GetInnerHTML(el.id)) 307 308 if err != nil { 309 return values.EmptyString, err 310 } 311 312 return values.ToString(out), nil 313 } 314 315 func (el *HTMLElement) SetInnerHTML(ctx context.Context, innerHTML values.String) error { 316 return el.eval.Eval(ctx, templates.SetInnerHTML(el.id, innerHTML)) 317 } 318 319 func (el *HTMLElement) GetInnerHTMLBySelector(ctx context.Context, selector drivers.QuerySelector) (values.String, error) { 320 out, err := el.eval.EvalValue(ctx, templates.GetInnerHTMLBySelector(el.id, selector)) 321 322 if err != nil { 323 return values.EmptyString, err 324 } 325 326 return values.ToString(out), nil 327 } 328 329 func (el *HTMLElement) SetInnerHTMLBySelector(ctx context.Context, selector drivers.QuerySelector, innerHTML values.String) error { 330 return el.eval.Eval(ctx, templates.SetInnerHTMLBySelector(el.id, selector, innerHTML)) 331 } 332 333 func (el *HTMLElement) GetInnerHTMLBySelectorAll(ctx context.Context, selector drivers.QuerySelector) (*values.Array, error) { 334 out, err := el.eval.EvalValue(ctx, templates.GetInnerHTMLBySelectorAll(el.id, selector)) 335 336 if err != nil { 337 return values.EmptyArray(), err 338 } 339 340 return values.ToArray(ctx, out), nil 341 } 342 343 func (el *HTMLElement) CountBySelector(ctx context.Context, selector drivers.QuerySelector) (values.Int, error) { 344 out, err := el.eval.EvalValue(ctx, templates.CountBySelector(el.id, selector)) 345 346 if err != nil { 347 return values.ZeroInt, err 348 } 349 350 return values.ToInt(out), nil 351 } 352 353 func (el *HTMLElement) ExistsBySelector(ctx context.Context, selector drivers.QuerySelector) (values.Boolean, error) { 354 out, err := el.eval.EvalValue(ctx, templates.ExistsBySelector(el.id, selector)) 355 356 if err != nil { 357 return values.False, err 358 } 359 360 return values.ToBoolean(out), nil 361 } 362 363 func (el *HTMLElement) WaitForElement(ctx context.Context, selector drivers.QuerySelector, when drivers.WaitEvent) error { 364 task := events.NewEvalWaitTask( 365 el.eval, 366 templates.WaitForElement(el.id, selector, when), 367 events.DefaultPolling, 368 ) 369 370 _, err := task.Run(ctx) 371 372 return err 373 } 374 375 func (el *HTMLElement) WaitForElementAll(ctx context.Context, selector drivers.QuerySelector, when drivers.WaitEvent) error { 376 task := events.NewEvalWaitTask( 377 el.eval, 378 templates.WaitForElementAll(el.id, selector, when), 379 events.DefaultPolling, 380 ) 381 382 _, err := task.Run(ctx) 383 384 return err 385 } 386 387 func (el *HTMLElement) WaitForClass(ctx context.Context, class values.String, when drivers.WaitEvent) error { 388 task := events.NewEvalWaitTask( 389 el.eval, 390 templates.WaitForClass(el.id, class, when), 391 events.DefaultPolling, 392 ) 393 394 _, err := task.Run(ctx) 395 396 return err 397 } 398 399 func (el *HTMLElement) WaitForClassBySelector(ctx context.Context, selector drivers.QuerySelector, class values.String, when drivers.WaitEvent) error { 400 task := events.NewEvalWaitTask( 401 el.eval, 402 templates.WaitForClassBySelector(el.id, selector, class, when), 403 events.DefaultPolling, 404 ) 405 406 _, err := task.Run(ctx) 407 408 return err 409 } 410 411 func (el *HTMLElement) WaitForClassBySelectorAll(ctx context.Context, selector drivers.QuerySelector, class values.String, when drivers.WaitEvent) error { 412 task := events.NewEvalWaitTask( 413 el.eval, 414 templates.WaitForClassBySelectorAll(el.id, selector, class, when), 415 events.DefaultPolling, 416 ) 417 418 _, err := task.Run(ctx) 419 420 return err 421 } 422 423 func (el *HTMLElement) WaitForAttribute( 424 ctx context.Context, 425 name values.String, 426 value core.Value, 427 when drivers.WaitEvent, 428 ) error { 429 task := events.NewEvalWaitTask( 430 el.eval, 431 templates.WaitForAttribute(el.id, name, value, when), 432 events.DefaultPolling, 433 ) 434 435 _, err := task.Run(ctx) 436 437 return err 438 } 439 440 func (el *HTMLElement) WaitForAttributeBySelector(ctx context.Context, selector drivers.QuerySelector, name values.String, value core.Value, when drivers.WaitEvent) error { 441 task := events.NewEvalWaitTask( 442 el.eval, 443 templates.WaitForAttributeBySelector(el.id, selector, name, value, when), 444 events.DefaultPolling, 445 ) 446 447 _, err := task.Run(ctx) 448 449 return err 450 } 451 452 func (el *HTMLElement) WaitForAttributeBySelectorAll(ctx context.Context, selector drivers.QuerySelector, name values.String, value core.Value, when drivers.WaitEvent) error { 453 task := events.NewEvalWaitTask( 454 el.eval, 455 templates.WaitForAttributeBySelectorAll(el.id, selector, name, value, when), 456 events.DefaultPolling, 457 ) 458 459 _, err := task.Run(ctx) 460 461 return err 462 } 463 464 func (el *HTMLElement) WaitForStyle(ctx context.Context, name values.String, value core.Value, when drivers.WaitEvent) error { 465 task := events.NewEvalWaitTask( 466 el.eval, 467 templates.WaitForStyle(el.id, name, value, when), 468 events.DefaultPolling, 469 ) 470 471 _, err := task.Run(ctx) 472 473 return err 474 } 475 476 func (el *HTMLElement) WaitForStyleBySelector(ctx context.Context, selector drivers.QuerySelector, name values.String, value core.Value, when drivers.WaitEvent) error { 477 task := events.NewEvalWaitTask( 478 el.eval, 479 templates.WaitForStyleBySelector(el.id, selector, name, value, when), 480 events.DefaultPolling, 481 ) 482 483 _, err := task.Run(ctx) 484 485 return err 486 } 487 488 func (el *HTMLElement) WaitForStyleBySelectorAll(ctx context.Context, selector drivers.QuerySelector, name values.String, value core.Value, when drivers.WaitEvent) error { 489 task := events.NewEvalWaitTask( 490 el.eval, 491 templates.WaitForStyleBySelectorAll(el.id, selector, name, value, when), 492 events.DefaultPolling, 493 ) 494 495 _, err := task.Run(ctx) 496 497 return err 498 } 499 500 func (el *HTMLElement) Click(ctx context.Context, count values.Int) error { 501 return el.input.Click(ctx, el.id, int(count)) 502 } 503 504 func (el *HTMLElement) ClickBySelector(ctx context.Context, selector drivers.QuerySelector, count values.Int) error { 505 return el.input.ClickBySelector(ctx, el.id, selector, count) 506 } 507 508 func (el *HTMLElement) ClickBySelectorAll(ctx context.Context, selector drivers.QuerySelector, count values.Int) error { 509 elements, err := el.QuerySelectorAll(ctx, selector) 510 511 if err != nil { 512 return err 513 } 514 515 elements.ForEach(func(value core.Value, idx int) bool { 516 found := value.(*HTMLElement) 517 518 if e := found.Click(ctx, count); e != nil { 519 err = e 520 return false 521 } 522 523 return true 524 }) 525 526 return err 527 } 528 529 func (el *HTMLElement) Input(ctx context.Context, value core.Value, delay values.Int) error { 530 name, err := el.GetNodeName(ctx) 531 532 if err != nil { 533 return err 534 } 535 536 if strings.ToLower(string(name)) != "input" { 537 return core.Error(core.ErrInvalidOperation, "element is not an <input> element.") 538 } 539 540 return el.input.Type(ctx, el.id, input.TypeParams{ 541 Text: value.String(), 542 Clear: false, 543 Delay: time.Duration(delay) * time.Millisecond, 544 }) 545 } 546 547 func (el *HTMLElement) InputBySelector(ctx context.Context, selector drivers.QuerySelector, value core.Value, delay values.Int) error { 548 return el.input.TypeBySelector(ctx, el.id, selector, input.TypeParams{ 549 Text: value.String(), 550 Clear: false, 551 Delay: time.Duration(delay) * time.Millisecond, 552 }) 553 } 554 555 func (el *HTMLElement) Press(ctx context.Context, keys []values.String, count values.Int) error { 556 return el.input.Press(ctx, values.UnwrapStrings(keys), int(count)) 557 } 558 559 func (el *HTMLElement) PressBySelector(ctx context.Context, selector drivers.QuerySelector, keys []values.String, count values.Int) error { 560 return el.input.PressBySelector(ctx, el.id, selector, values.UnwrapStrings(keys), int(count)) 561 } 562 563 func (el *HTMLElement) Clear(ctx context.Context) error { 564 return el.input.Clear(ctx, el.id) 565 } 566 567 func (el *HTMLElement) ClearBySelector(ctx context.Context, selector drivers.QuerySelector) error { 568 return el.input.ClearBySelector(ctx, el.id, selector) 569 } 570 571 func (el *HTMLElement) Select(ctx context.Context, value *values.Array) (*values.Array, error) { 572 return el.input.Select(ctx, el.id, value) 573 } 574 575 func (el *HTMLElement) SelectBySelector(ctx context.Context, selector drivers.QuerySelector, value *values.Array) (*values.Array, error) { 576 return el.input.SelectBySelector(ctx, el.id, selector, value) 577 } 578 579 func (el *HTMLElement) ScrollIntoView(ctx context.Context, options drivers.ScrollOptions) error { 580 return el.input.ScrollIntoView(ctx, el.id, options) 581 } 582 583 func (el *HTMLElement) Focus(ctx context.Context) error { 584 return el.input.Focus(ctx, el.id) 585 } 586 587 func (el *HTMLElement) FocusBySelector(ctx context.Context, selector drivers.QuerySelector) error { 588 return el.input.FocusBySelector(ctx, el.id, selector) 589 } 590 591 func (el *HTMLElement) Blur(ctx context.Context) error { 592 return el.input.Blur(ctx, el.id) 593 } 594 595 func (el *HTMLElement) BlurBySelector(ctx context.Context, selector drivers.QuerySelector) error { 596 return el.input.BlurBySelector(ctx, el.id, selector) 597 } 598 599 func (el *HTMLElement) Hover(ctx context.Context) error { 600 return el.input.MoveMouse(ctx, el.id) 601 } 602 603 func (el *HTMLElement) HoverBySelector(ctx context.Context, selector drivers.QuerySelector) error { 604 return el.input.MoveMouseBySelector(ctx, el.id, selector) 605 } 606 607 func (el *HTMLElement) logError(err error) *zerolog.Event { 608 return el.logger. 609 Error(). 610 Timestamp(). 611 Str("objectID", string(el.id)). 612 Err(err) 613 }