mirror of
https://github.com/MontFerret/ferret.git
synced 2025-05-31 23:09:43 +02:00
Feature/#250 wait style 2 (#260)
* Added WAIT_STYLE and WAIT_NO_STYLE * Added WAIT_NO_STYLE and WAIT_NO_STYLE_ALL functions
This commit is contained in:
parent
82f7317ebe
commit
e17ce5a3d5
30
e2e/tests/doc_wait_no_style_all_d.fql
Normal file
30
e2e/tests/doc_wait_no_style_all_d.fql
Normal file
@ -0,0 +1,30 @@
|
||||
LET url = @dynamic + "?redirect=/events"
|
||||
LET doc = DOCUMENT(url, true)
|
||||
LET selector = "#wait-class-btn, #wait-class-random-btn"
|
||||
|
||||
WAIT_ELEMENT(doc, "#page-events")
|
||||
|
||||
LET n = (
|
||||
FOR el IN ELEMENTS(doc, selector)
|
||||
ATTR_SET(el, "style", "color: black")
|
||||
|
||||
RETURN NONE
|
||||
)
|
||||
|
||||
WAIT_STYLE_ALL(doc, selector, "color", "black", 10000)
|
||||
|
||||
LET n2 = (
|
||||
FOR el IN ELEMENTS(doc, selector)
|
||||
ATTR_SET(el, "style", "color: red")
|
||||
|
||||
RETURN NONE
|
||||
)
|
||||
|
||||
WAIT_NO_STYLE_ALL(doc, selector, "color", "black", 10000)
|
||||
|
||||
LET results = (
|
||||
FOR el IN ELEMENTS(doc, selector)
|
||||
RETURN el.style.color
|
||||
)
|
||||
|
||||
RETURN CONCAT(results) == "redred" ? "" : "styles should be updated"
|
19
e2e/tests/doc_wait_no_style_d.fql
Normal file
19
e2e/tests/doc_wait_no_style_d.fql
Normal file
@ -0,0 +1,19 @@
|
||||
LET url = @dynamic + "?redirect=/events"
|
||||
LET doc = DOCUMENT(url, true)
|
||||
LET selector = "#wait-class-btn"
|
||||
|
||||
WAIT_ELEMENT(doc, "#page-events")
|
||||
|
||||
LET el = ELEMENT(doc, selector)
|
||||
|
||||
ATTR_SET(el, "style", "width: 100%")
|
||||
WAIT_STYLE(doc, selector, "width", "100%")
|
||||
|
||||
LET prev = el.style
|
||||
|
||||
ATTR_SET(el, "style", "width: 50%")
|
||||
WAIT_NO_STYLE(doc, selector, "width", "100%")
|
||||
|
||||
LET curr = el.style
|
||||
|
||||
RETURN prev.width == "100%" && curr.width == "50%" ? "" : "style should be changed"
|
21
e2e/tests/doc_wait_style_all_d.fql
Normal file
21
e2e/tests/doc_wait_style_all_d.fql
Normal file
@ -0,0 +1,21 @@
|
||||
LET url = @dynamic + "?redirect=/events"
|
||||
LET doc = DOCUMENT(url, true)
|
||||
LET selector = "#wait-class-btn, #wait-class-random-btn"
|
||||
|
||||
WAIT_ELEMENT(doc, "#page-events")
|
||||
|
||||
LET n = (
|
||||
FOR el IN ELEMENTS(doc, selector)
|
||||
ATTR_SET(el, "style", "color: black")
|
||||
|
||||
RETURN NONE
|
||||
)
|
||||
|
||||
WAIT_STYLE_ALL(doc, selector, "color", "black", 10000)
|
||||
|
||||
LET results = (
|
||||
FOR el IN ELEMENTS(doc, selector)
|
||||
RETURN el.style.color
|
||||
)
|
||||
|
||||
RETURN CONCAT(results) == "blackblack" ? "" : "styles should be updated"
|
15
e2e/tests/doc_wait_style_d.fql
Normal file
15
e2e/tests/doc_wait_style_d.fql
Normal file
@ -0,0 +1,15 @@
|
||||
LET url = @dynamic + "?redirect=/events"
|
||||
LET doc = DOCUMENT(url, true)
|
||||
LET selector = "#wait-class-btn"
|
||||
|
||||
WAIT_ELEMENT(doc, "#page-events")
|
||||
|
||||
LET el = ELEMENT(doc, selector)
|
||||
LET prev = el.style
|
||||
|
||||
ATTR_SET(el, "style", "width: 100%")
|
||||
WAIT_STYLE(doc, selector, "width", "100%")
|
||||
|
||||
LET curr = el.style
|
||||
|
||||
RETURN prev.width == NONE && curr.width == "100%" ? "" : "style should be updated"
|
18
e2e/tests/el_wait_no_style_d.fql
Normal file
18
e2e/tests/el_wait_no_style_d.fql
Normal file
@ -0,0 +1,18 @@
|
||||
LET url = @dynamic + "?redirect=/events"
|
||||
LET doc = DOCUMENT(url, true)
|
||||
|
||||
WAIT_ELEMENT(doc, "#page-events")
|
||||
|
||||
LET el = ELEMENT(doc, "#wait-class-content")
|
||||
|
||||
ATTR_SET(el, "style", "color: black")
|
||||
WAIT_STYLE(el, "color", "black")
|
||||
|
||||
LET prev = el.style
|
||||
|
||||
ATTR_SET(el, "style", "color: red")
|
||||
WAIT_NO_STYLE(el, "color", "black")
|
||||
|
||||
LET curr = el.style
|
||||
|
||||
RETURN prev.color == "black" && curr.color == "red" ? "" : "style should be changed"
|
18
e2e/tests/el_wait_style_d.fql
Normal file
18
e2e/tests/el_wait_style_d.fql
Normal file
@ -0,0 +1,18 @@
|
||||
LET url = @dynamic + "?redirect=/events"
|
||||
LET doc = DOCUMENT(url, true)
|
||||
|
||||
WAIT_ELEMENT(doc, "#page-events")
|
||||
|
||||
LET el = ELEMENT(doc, "#wait-class-content")
|
||||
|
||||
ATTR_SET(el, "style", "color: black")
|
||||
WAIT_STYLE(el, "color", "black")
|
||||
|
||||
LET prev = el.style
|
||||
|
||||
ATTR_REMOVE(el, "style")
|
||||
WAIT_STYLE(el, "color", NONE)
|
||||
|
||||
LET curr = el.style
|
||||
|
||||
RETURN prev.color == "black" && curr.color == NONE ? "" : "style should be removed"
|
@ -658,6 +658,40 @@ func (doc *HTMLDocument) WaitForAttributeBySelectorAll(
|
||||
return err
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForStyleBySelector(ctx context.Context, selector, name values.String, value core.Value, when drivers.WaitEvent) error {
|
||||
task := events.NewEvalWaitTask(
|
||||
doc.client,
|
||||
templates.WaitBySelector(
|
||||
selector,
|
||||
when,
|
||||
value,
|
||||
templates.StyleRead(name),
|
||||
),
|
||||
events.DefaultPolling,
|
||||
)
|
||||
|
||||
_, err := task.Run(ctx)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForStyleBySelectorAll(ctx context.Context, selector, name values.String, value core.Value, when drivers.WaitEvent) error {
|
||||
task := events.NewEvalWaitTask(
|
||||
doc.client,
|
||||
templates.WaitBySelectorAll(
|
||||
selector,
|
||||
when,
|
||||
value,
|
||||
templates.StyleRead(name),
|
||||
),
|
||||
events.DefaultPolling,
|
||||
)
|
||||
|
||||
_, err := task.Run(ctx)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) Navigate(ctx context.Context, url values.String) error {
|
||||
if url == "" {
|
||||
url = BlankPageURL
|
||||
|
@ -867,30 +867,19 @@ func (el *HTMLElement) WaitForAttribute(
|
||||
value core.Value,
|
||||
when drivers.WaitEvent,
|
||||
) error {
|
||||
task := events.NewWaitTask(
|
||||
func(ctx2 context.Context) (core.Value, error) {
|
||||
current := el.GetAttribute(ctx2, name)
|
||||
task := events.NewValueWaitTask(when, value, func(ctx context.Context) (core.Value, error) {
|
||||
return el.GetAttribute(ctx, name), nil
|
||||
}, events.DefaultPolling)
|
||||
|
||||
if when == drivers.WaitEventPresence {
|
||||
// Values appeared, exit
|
||||
if current.Compare(value) == 0 {
|
||||
// The value does not really matter if it's not None
|
||||
// None indicates that operation needs to be repeated
|
||||
return values.True, nil
|
||||
}
|
||||
} else {
|
||||
// Value disappeared, exit
|
||||
if current.Compare(value) != 0 {
|
||||
// The value does not really matter if it's not None
|
||||
// None indicates that operation needs to be repeated
|
||||
return values.True, nil
|
||||
}
|
||||
}
|
||||
_, err := task.Run(ctx)
|
||||
|
||||
return values.None, nil
|
||||
},
|
||||
events.DefaultPolling,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (el *HTMLElement) WaitForStyle(ctx context.Context, name values.String, value core.Value, when drivers.WaitEvent) error {
|
||||
task := events.NewValueWaitTask(when, value, func(ctx context.Context) (core.Value, error) {
|
||||
return el.GetStyle(ctx, name)
|
||||
}, events.DefaultPolling)
|
||||
|
||||
_, err := task.Run(ctx)
|
||||
|
||||
|
@ -2,6 +2,7 @@ package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/drivers"
|
||||
"github.com/MontFerret/ferret/pkg/drivers/cdp/eval"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
@ -74,3 +75,39 @@ func NewEvalWaitTask(
|
||||
polling,
|
||||
)
|
||||
}
|
||||
|
||||
func NewValueWaitTask(
|
||||
when drivers.WaitEvent,
|
||||
value core.Value,
|
||||
getter Function,
|
||||
polling time.Duration,
|
||||
) *WaitTask {
|
||||
return &WaitTask{
|
||||
func(ctx context.Context) (core.Value, error) {
|
||||
current, err := getter(ctx)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
if when == drivers.WaitEventPresence {
|
||||
// Values appeared, exit
|
||||
if current.Compare(value) == 0 {
|
||||
// The value does not really matter if it's not None
|
||||
// None indicates that operation needs to be repeated
|
||||
return values.True, nil
|
||||
}
|
||||
} else {
|
||||
// Value disappeared, exit
|
||||
if current.Compare(value) != 0 {
|
||||
// The value does not really matter if it's not None
|
||||
// None indicates that operation needs to be repeated
|
||||
return values.True, nil
|
||||
}
|
||||
}
|
||||
|
||||
return values.None, nil
|
||||
},
|
||||
polling,
|
||||
}
|
||||
}
|
||||
|
15
pkg/drivers/cdp/templates/styles.go
Normal file
15
pkg/drivers/cdp/templates/styles.go
Normal file
@ -0,0 +1,15 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/drivers/cdp/eval"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
)
|
||||
|
||||
func StyleRead(name values.String) string {
|
||||
n := name.String()
|
||||
return fmt.Sprintf(`
|
||||
el.style[%s] != "" ? el.style[%s] : null
|
||||
`, eval.ParamString(n), eval.ParamString(n))
|
||||
}
|
@ -245,6 +245,14 @@ func (doc *HTMLDocument) WaitForAttributeBySelectorAll(_ context.Context, _, _ v
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForStyleBySelector(_ context.Context, _, _ values.String, _ core.Value, _ drivers.WaitEvent) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForStyleBySelectorAll(_ context.Context, _, _ values.String, _ core.Value, _ drivers.WaitEvent) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
@ -410,6 +410,10 @@ func (el *HTMLElement) WaitForAttribute(_ context.Context, _ values.String, _ co
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (el *HTMLElement) WaitForStyle(_ context.Context, _ values.String, _ core.Value, _ drivers.WaitEvent) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (el *HTMLElement) ensureStyles(ctx context.Context) error {
|
||||
if el.styles == nil {
|
||||
styles, err := el.parseStyles(ctx)
|
||||
|
@ -91,9 +91,11 @@ type (
|
||||
|
||||
Hover(ctx context.Context) error
|
||||
|
||||
WaitForClass(ctx context.Context, class values.String, when WaitEvent) error
|
||||
|
||||
WaitForAttribute(ctx context.Context, name values.String, value core.Value, when WaitEvent) error
|
||||
|
||||
WaitForStyle(ctx context.Context, name values.String, value core.Value, when WaitEvent) error
|
||||
|
||||
WaitForClass(ctx context.Context, class values.String, when WaitEvent) error
|
||||
}
|
||||
|
||||
// The Document interface represents any web page loaded in the browser
|
||||
@ -141,13 +143,17 @@ type (
|
||||
|
||||
WaitForElement(ctx context.Context, selector values.String, when WaitEvent) error
|
||||
|
||||
WaitForClassBySelector(ctx context.Context, selector, class values.String, when WaitEvent) error
|
||||
|
||||
WaitForClassBySelectorAll(ctx context.Context, selector, class values.String, when WaitEvent) error
|
||||
|
||||
WaitForAttributeBySelector(ctx context.Context, selector, name values.String, value core.Value, when WaitEvent) error
|
||||
|
||||
WaitForAttributeBySelectorAll(ctx context.Context, selector, name values.String, value core.Value, when WaitEvent) error
|
||||
|
||||
WaitForStyleBySelector(ctx context.Context, selector, name values.String, value core.Value, when WaitEvent) error
|
||||
|
||||
WaitForStyleBySelectorAll(ctx context.Context, selector, name values.String, value core.Value, when WaitEvent) error
|
||||
|
||||
WaitForClassBySelector(ctx context.Context, selector, class values.String, when WaitEvent) error
|
||||
|
||||
WaitForClassBySelectorAll(ctx context.Context, selector, class values.String, when WaitEvent) error
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -56,6 +56,10 @@ func NewLib() map[string]core.Function {
|
||||
"WAIT_NO_CLASS": WaitNoClass,
|
||||
"WAIT_CLASS_ALL": WaitClassAll,
|
||||
"WAIT_NO_CLASS_ALL": WaitNoClassAll,
|
||||
"WAIT_STYLE": WaitStyle,
|
||||
"WAIT_NO_STYLE": WaitNoStyle,
|
||||
"WAIT_STYLE_ALL": WaitStyleAll,
|
||||
"WAIT_NO_STYLE_ALL": WaitNoStyleAll,
|
||||
"WAIT_NAVIGATION": WaitNavigation,
|
||||
}
|
||||
}
|
||||
|
100
pkg/stdlib/html/wait_style.go
Normal file
100
pkg/stdlib/html/wait_style.go
Normal file
@ -0,0 +1,100 @@
|
||||
package html
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func WaitStyle(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
return waitStyleWhen(ctx, args, drivers.WaitEventPresence)
|
||||
}
|
||||
|
||||
func WaitNoStyle(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
return waitStyleWhen(ctx, args, drivers.WaitEventAbsence)
|
||||
}
|
||||
|
||||
func waitStyleWhen(ctx context.Context, args []core.Value, when drivers.WaitEvent) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 3, 5)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
// document or element
|
||||
arg1 := args[0]
|
||||
err = core.ValidateType(arg1, drivers.HTMLDocumentType, drivers.HTMLElementType)
|
||||
|
||||
if err != nil {
|
||||
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(defaultTimeout)
|
||||
|
||||
// if a document is passed
|
||||
// WAIT_ATTR(doc, selector, attrName, attrValue, timeout)
|
||||
if arg1.Type() == drivers.HTMLDocumentType {
|
||||
// revalidate args with more accurate amount
|
||||
err := core.ValidateArgs(args, 4, 5)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
// attr name
|
||||
err = core.ValidateType(args[2], types.String)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
doc := arg1.(drivers.HTMLDocument)
|
||||
selector := args[1].(values.String)
|
||||
name := args[2].(values.String)
|
||||
value := args[3]
|
||||
|
||||
if len(args) == 5 {
|
||||
err = core.ValidateType(args[4], types.Int)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
timeout = args[4].(values.Int)
|
||||
}
|
||||
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return values.None, doc.WaitForStyleBySelector(ctx, selector, name, value, when)
|
||||
}
|
||||
|
||||
el := arg1.(drivers.HTMLElement)
|
||||
name := args[1].(values.String)
|
||||
value := args[2]
|
||||
|
||||
if len(args) == 4 {
|
||||
err = core.ValidateType(args[3], types.Int)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
timeout = args[3].(values.Int)
|
||||
}
|
||||
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return values.None, el.WaitForStyle(ctx, name, value, when)
|
||||
}
|
65
pkg/stdlib/html/wait_style_all.go
Normal file
65
pkg/stdlib/html/wait_style_all.go
Normal file
@ -0,0 +1,65 @@
|
||||
package html
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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"
|
||||
)
|
||||
|
||||
func WaitStyleAll(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
return waitStyleAllWhen(ctx, args, drivers.WaitEventPresence)
|
||||
}
|
||||
|
||||
func WaitNoStyleAll(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
return waitStyleAllWhen(ctx, args, drivers.WaitEventAbsence)
|
||||
}
|
||||
|
||||
func waitStyleAllWhen(ctx context.Context, args []core.Value, when drivers.WaitEvent) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 4, 5)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
doc, err := toDocument(args[0])
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
// selector
|
||||
err = core.ValidateType(args[1], types.String)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
// attr name
|
||||
err = core.ValidateType(args[2], types.String)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
selector := args[1].(values.String)
|
||||
name := args[2].(values.String)
|
||||
value := args[3]
|
||||
timeout := values.NewInt(defaultTimeout)
|
||||
|
||||
if len(args) == 5 {
|
||||
err = core.ValidateType(args[4], types.Int)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
timeout = args[4].(values.Int)
|
||||
}
|
||||
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return values.None, doc.WaitForStyleBySelectorAll(ctx, selector, name, value, when)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user