1
0
mirror of https://github.com/MontFerret/ferret.git synced 2025-12-01 22:19:32 +02:00

Feature/new selector type (#657)

* Added remote type reference resolver

* Added support of XPath query selector

* Added CDP e2e testss covering XPath integration

* Added additional CDP e2e tests covering XPath integration

* Added type check to QuerySelector casting function

* Fixed XPath e2e tests

* Fixed vuln issue

* Added support of XPath selectors to http driver

* Added e2e tests for XPAth
This commit is contained in:
Tim Voronov
2021-09-16 21:40:20 -04:00
committed by GitHub
parent a000302259
commit 90427cd537
167 changed files with 2275 additions and 1102 deletions

View File

@@ -26,7 +26,13 @@ func AttributeQuery(ctx context.Context, args ...core.Value) (core.Value, error)
return values.None, err
}
found, err := parent.QuerySelector(ctx, values.ToString(args[1]))
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
found, err := parent.QuerySelector(ctx, selector)
if err != nil {
return values.None, err

View File

@@ -28,5 +28,11 @@ func Blur(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, el.Blur(ctx)
}
return values.None, el.BlurBySelector(ctx, values.ToString(args[1]))
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
return values.None, el.BlurBySelector(ctx, selector)
}

View File

@@ -29,5 +29,11 @@ func InputClear(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, el.Clear(ctx)
}
return values.True, el.ClearBySelector(ctx, values.ToString(args[1]))
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
return values.True, el.ClearBySelector(ctx, selector)
}

View File

@@ -32,14 +32,19 @@ func Click(ctx context.Context, args ...core.Value) (core.Value, error) {
}
if len(args) == 2 {
err := core.ValidateType(args[1], types.String, types.Int)
err := core.ValidateType(args[1], types.String, types.Int, drivers.QuerySelectorType)
if err != nil {
return values.False, err
}
if args[1].Type() == types.String {
selector := values.ToString(args[1])
if args[1].Type() == types.String || args[1].Type() == drivers.QuerySelectorType {
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
exists, err := el.ExistsBySelector(ctx, selector)
if err != nil {
@@ -56,12 +61,6 @@ func Click(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.True, el.Click(ctx, values.ToInt(args[1]))
}
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.False, err
}
err = core.ValidateType(args[2], types.Int)
if err != nil {
@@ -69,7 +68,12 @@ func Click(ctx context.Context, args ...core.Value) (core.Value, error) {
}
// CLICK(doc, selector)
selector := values.ToString(args[1])
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
exists, err := el.ExistsBySelector(ctx, selector)
if err != nil {

View File

@@ -27,7 +27,11 @@ func ClickAll(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.False, err
}
selector := values.ToString(args[1])
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
exists, err := el.ExistsBySelector(ctx, selector)

View File

@@ -6,7 +6,6 @@ import (
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// ELEMENT finds an element by a given CSS selector.
@@ -24,24 +23,24 @@ func Element(ctx context.Context, args ...core.Value) (core.Value, error) {
return el.QuerySelector(ctx, selector)
}
func queryArgs(args []core.Value) (drivers.HTMLElement, values.String, error) {
func queryArgs(args []core.Value) (drivers.HTMLElement, drivers.QuerySelector, error) {
err := core.ValidateArgs(args, 2, 2)
if err != nil {
return nil, values.EmptyString, err
return nil, drivers.QuerySelector{}, err
}
el, err := drivers.ToElement(args[0])
if err != nil {
return nil, values.EmptyString, err
return nil, drivers.QuerySelector{}, err
}
err = core.ValidateType(args[1], types.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return nil, values.EmptyString, err
return nil, drivers.QuerySelector{}, err
}
return el, args[1].(values.String), nil
return el, selector, nil
}

View File

@@ -28,5 +28,11 @@ func Focus(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.True, el.Focus(ctx)
}
return values.True, el.FocusBySelector(ctx, values.ToString(args[1]))
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
return values.True, el.FocusBySelector(ctx, selector)
}

View File

@@ -6,7 +6,6 @@ import (
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// INNER_HTML returns inner HTML string of a given or matched by CSS selector element
@@ -30,13 +29,11 @@ func GetInnerHTML(ctx context.Context, args ...core.Value) (core.Value, error) {
return el.GetInnerHTML(ctx)
}
err = core.ValidateType(args[1], types.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
selector := args[1].(values.String)
return el.GetInnerHTMLBySelector(ctx, selector)
}

View File

@@ -6,7 +6,6 @@ import (
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// INNER_HTML_ALL returns an array of inner HTML strings of matched elements.
@@ -20,19 +19,17 @@ func GetInnerHTMLAll(ctx context.Context, args ...core.Value) (core.Value, error
return values.None, err
}
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err
}
el, err := drivers.ToElement(args[0])
if err != nil {
return values.None, err
}
selector := args[1].(values.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
return el.GetInnerHTMLBySelectorAll(ctx, selector)
}

View File

@@ -6,7 +6,6 @@ import (
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// INNER_TEXT returns inner text string of a given or matched by CSS selector element
@@ -30,13 +29,11 @@ func GetInnerText(ctx context.Context, args ...core.Value) (core.Value, error) {
return el.GetInnerText(ctx)
}
err = core.ValidateType(args[1], types.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
selector := args[1].(values.String)
return el.GetInnerTextBySelector(ctx, selector)
}

View File

@@ -6,7 +6,6 @@ import (
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// INNER_TEXT_ALL returns an array of inner text of matched elements.
@@ -20,19 +19,17 @@ func GetInnerTextAll(ctx context.Context, args ...core.Value) (core.Value, error
return values.None, err
}
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err
}
el, err := drivers.ToElement(args[0])
if err != nil {
return values.None, err
}
selector := args[1].(values.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
return el.GetInnerTextBySelectorAll(ctx, selector)
}

View File

@@ -6,7 +6,6 @@ import (
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// HOVER fetches an element with selector, scrolls it into view if needed, and then uses page.mouse to hover over the center of the element.
@@ -30,11 +29,11 @@ func Hover(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.True, el.Hover(ctx)
}
err = core.ValidateType(args[1], types.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
return values.True, el.HoverBySelector(ctx, values.ToString(args[1]))
return values.True, el.HoverBySelector(ctx, selector)
}

View File

@@ -34,7 +34,7 @@ func Input(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.True, el.Input(ctx, args[1], delay)
}
var selector values.String
var selector drivers.QuerySelector
var value core.Value
// INPUT(el, valueOrSelector, valueOrOpts)
@@ -48,24 +48,26 @@ func Input(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.True, el.Input(ctx, value, delay)
default:
// INPUT(el, selector, value)
if err := core.ValidateType(args[1], types.String); err != nil {
return values.False, err
selector, err = drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
selector = values.ToString(args[1])
value = args[2]
}
} else {
// INPUT(el, selector, value, delay)
if err := core.ValidateType(args[1], types.String); err != nil {
return values.False, err
}
if err := core.ValidateType(args[3], types.Int); err != nil {
return values.False, err
}
selector = values.ToString(args[1])
selector, err = drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
value = args[2]
delay = values.ToInt(args[3])
}

View File

@@ -75,6 +75,7 @@ func RegisterLib(ns core.Namespace) error {
"WAIT_NO_STYLE_ALL": WaitNoStyleAll,
"WAIT_NAVIGATION": WaitNavigation,
"XPATH": XPath,
"X": XPathSelector,
}))
}

View File

@@ -6,7 +6,6 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/logging"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
"github.com/rs/zerolog"
)
@@ -28,14 +27,12 @@ func Pagination(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[1], types.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
selector := args[1].(values.String)
logger := logging.
WithName(logging.FromContext(ctx).With(), "stdlib_html_pagination").
Str("selector", selector.String()).
@@ -50,13 +47,13 @@ type (
Paging struct {
logger zerolog.Logger
page drivers.HTMLPage
selector values.String
selector drivers.QuerySelector
}
PagingIterator struct {
logger zerolog.Logger
page drivers.HTMLPage
selector values.String
selector drivers.QuerySelector
pos values.Int
}
)

View File

@@ -27,7 +27,11 @@ func PressSelector(ctx context.Context, args ...core.Value) (core.Value, error)
return values.False, err
}
selector := values.ToString(args[1])
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
count := values.NewInt(1)

View File

@@ -27,7 +27,7 @@ func ScrollInto(ctx context.Context, args ...core.Value) (core.Value, error) {
var doc drivers.HTMLDocument
var el drivers.HTMLElement
var selector values.String
var selector drivers.QuerySelector
var opts drivers.ScrollOptions
if len(args) == 3 {
@@ -45,7 +45,12 @@ func ScrollInto(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, errors.Wrap(err, "document")
}
selector = values.ToString(args[1])
selector, err = drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
o, err := toScrollOptions(args[2])
if err != nil {
@@ -65,7 +70,12 @@ func ScrollInto(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, errors.Wrap(err, "document")
}
selector = values.ToString(args[1])
selector, err = drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
} else {
el, err = drivers.ToElement(args[0])
o, err := toScrollOptions(args[1])
@@ -85,7 +95,7 @@ func ScrollInto(ctx context.Context, args ...core.Value) (core.Value, error) {
}
if doc != nil {
if selector != values.EmptyString {
if selector.String() != "" {
return values.True, doc.ScrollBySelector(ctx, selector, opts)
}

View File

@@ -32,7 +32,12 @@ func Select(ctx context.Context, args ...core.Value) (core.Value, error) {
return el.Select(ctx, arr)
}
selector := values.ToString(args[1])
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
arr := values.ToArray(ctx, args[2])
return el.SelectBySelector(ctx, selector, arr)

View File

@@ -36,7 +36,7 @@ func SetInnerHTML(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, el.SetInnerHTML(ctx, values.ToString(args[1]))
}
err = core.ValidateType(args[1], types.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
@@ -48,7 +48,6 @@ func SetInnerHTML(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
selector := values.ToString(args[1])
innerHTML := values.ToString(args[2])
return values.None, el.SetInnerHTMLBySelector(ctx, selector, innerHTML)

View File

@@ -36,19 +36,18 @@ func SetInnerText(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, el.SetInnerText(ctx, values.ToString(args[1]))
}
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[2], types.String)
if err != nil {
return values.None, err
}
selector := values.ToString(args[1])
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
innerHTML := values.ToString(args[2])
return values.None, el.SetInnerTextBySelector(ctx, selector, innerHTML)

View File

@@ -44,13 +44,6 @@ func waitAttributeWhen(ctx context.Context, args []core.Value, when drivers.Wait
return values.None, err
}
// selector or attr name
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err
}
timeout := values.NewInt(drivers.DefaultWaitTimeout)
// if a document is passed
@@ -76,7 +69,12 @@ func waitAttributeWhen(ctx context.Context, args []core.Value, when drivers.Wait
return values.None, err
}
selector := args[1].(values.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
name := args[2].(values.String)
value := values.ToString(args[3])

View File

@@ -42,8 +42,7 @@ func waitAttributeAllWhen(ctx context.Context, args []core.Value, when drivers.W
return values.None, err
}
// selector
err = core.ValidateType(args[1], types.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
@@ -56,7 +55,6 @@ func waitAttributeAllWhen(ctx context.Context, args []core.Value, when drivers.W
return values.None, err
}
selector := args[1].(values.String)
name := args[2].(values.String)
value := args[3]
timeout := values.NewInt(drivers.DefaultWaitTimeout)

View File

@@ -44,13 +44,6 @@ func waitClassWhen(ctx context.Context, args []core.Value, when drivers.WaitEven
return values.None, err
}
// selector or class
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err
}
timeout := values.NewInt(drivers.DefaultWaitTimeout)
// if a document is passed
@@ -62,6 +55,12 @@ func waitClassWhen(ctx context.Context, args []core.Value, when drivers.WaitEven
return values.None, err
}
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
// class
err = core.ValidateType(args[2], types.String)
@@ -75,7 +74,6 @@ func waitClassWhen(ctx context.Context, args []core.Value, when drivers.WaitEven
return values.None, err
}
selector := args[1].(values.String)
class := args[2].(values.String)
if len(args) == 4 {

View File

@@ -43,7 +43,7 @@ func waitClassAllWhen(ctx context.Context, args []core.Value, when drivers.WaitE
}
// selector
err = core.ValidateType(args[1], types.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
@@ -56,7 +56,6 @@ func waitClassAllWhen(ctx context.Context, args []core.Value, when drivers.WaitE
return values.None, err
}
selector := args[1].(values.String)
class := args[2].(values.String)
timeout := values.NewInt(drivers.DefaultWaitTimeout)

View File

@@ -40,7 +40,12 @@ func waitElementWhen(ctx context.Context, args []core.Value, when drivers.WaitEv
return values.None, err
}
selector := args[1].String()
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
timeout := values.NewInt(drivers.DefaultWaitTimeout)
if len(args) > 2 {
@@ -56,5 +61,5 @@ func waitElementWhen(ctx context.Context, args []core.Value, when drivers.WaitEv
ctx, fn := waitTimeout(ctx, timeout)
defer fn()
return values.True, el.WaitForElement(ctx, values.NewString(selector), when)
return values.True, el.WaitForElement(ctx, selector, when)
}

View File

@@ -44,13 +44,6 @@ func waitStyleWhen(ctx context.Context, args []core.Value, when drivers.WaitEven
return values.None, err
}
// selector or attr name
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err
}
timeout := values.NewInt(drivers.DefaultWaitTimeout)
// if a document is passed
@@ -63,6 +56,12 @@ func waitStyleWhen(ctx context.Context, args []core.Value, when drivers.WaitEven
return values.None, err
}
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
}
// attr name
err = core.ValidateType(args[2], types.String)
@@ -76,7 +75,6 @@ func waitStyleWhen(ctx context.Context, args []core.Value, when drivers.WaitEven
return values.None, err
}
selector := args[1].(values.String)
name := args[2].(values.String)
value := args[3]

View File

@@ -43,7 +43,7 @@ func waitStyleAllWhen(ctx context.Context, args []core.Value, when drivers.WaitE
}
// selector
err = core.ValidateType(args[1], types.String)
selector, err := drivers.ToQuerySelector(args[1])
if err != nil {
return values.None, err
@@ -56,7 +56,6 @@ func waitStyleAllWhen(ctx context.Context, args []core.Value, when drivers.WaitE
return values.None, err
}
selector := args[1].(values.String)
name := args[2].(values.String)
value := args[3]
timeout := values.NewInt(drivers.DefaultWaitTimeout)

View File

@@ -0,0 +1,20 @@
package html
import (
"context"
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
)
// X returns QuerySelector of XPath kind.
// @param {String} expression - XPath expression.
// @return {Any} - Returns QuerySelector of XPath kind.
func XPathSelector(_ context.Context, args ...core.Value) (core.Value, error) {
if err := core.ValidateArgs(args, 1, 1); err != nil {
return values.None, err
}
return drivers.NewXPathSelector(values.ToString(args[0])), nil
}