mirror of
https://github.com/MontFerret/ferret.git
synced 2025-01-26 03:51:57 +02:00
Added Context to HTML methods (#235)
* Added Context to HTML methods * Fixed unit tests * Updated timeout * Fixed WAIT_CLASS timeout
This commit is contained in:
parent
34c8c02258
commit
6e15846d0f
@ -53,7 +53,20 @@ func New(logger zerolog.Logger, settings Settings) *Runner {
|
||||
}
|
||||
|
||||
func (r *Runner) Run() error {
|
||||
results, err := r.runQueries(r.settings.Dir)
|
||||
ctx := context.Background()
|
||||
|
||||
ctx = drivers.WithContext(
|
||||
ctx,
|
||||
cdp.NewDriver(cdp.WithAddress(r.settings.CDPAddress)),
|
||||
)
|
||||
|
||||
ctx = drivers.WithContext(
|
||||
ctx,
|
||||
http.NewDriver(),
|
||||
drivers.AsDefault(),
|
||||
)
|
||||
|
||||
results, err := r.runQueries(ctx, r.settings.Dir)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@ -83,7 +96,7 @@ func (r *Runner) Run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) runQueries(dir string) ([]Result, error) {
|
||||
func (r *Runner) runQueries(ctx context.Context, dir string) ([]Result, error) {
|
||||
files, err := ioutil.ReadDir(dir)
|
||||
|
||||
if err != nil {
|
||||
@ -126,13 +139,30 @@ func (r *Runner) runQueries(dir string) ([]Result, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
results = append(results, r.runQuery(c, fName, string(b)))
|
||||
r.logger.Info().Timestamp().Str("name", fName).Msg("Running test")
|
||||
|
||||
result := r.runQuery(ctx, c, fName, string(b))
|
||||
|
||||
if result.err == nil {
|
||||
r.logger.Info().
|
||||
Timestamp().
|
||||
Str("file", result.name).
|
||||
Msg("Test passed")
|
||||
} else {
|
||||
r.logger.Error().
|
||||
Timestamp().
|
||||
Err(result.err).
|
||||
Str("file", result.name).
|
||||
Msg("Test failed")
|
||||
}
|
||||
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (r *Runner) runQuery(c *compiler.FqlCompiler, name, script string) Result {
|
||||
func (r *Runner) runQuery(ctx context.Context, c *compiler.FqlCompiler, name, script string) Result {
|
||||
start := time.Now()
|
||||
|
||||
p, err := c.Compile(script)
|
||||
@ -145,20 +175,6 @@ func (r *Runner) runQuery(c *compiler.FqlCompiler, name, script string) Result {
|
||||
}
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = drivers.WithContext(
|
||||
ctx,
|
||||
cdp.NewDriver(cdp.WithAddress(r.settings.CDPAddress)),
|
||||
)
|
||||
|
||||
ctx = drivers.WithContext(
|
||||
ctx,
|
||||
http.NewDriver(),
|
||||
drivers.AsDefault(),
|
||||
)
|
||||
|
||||
r.logger.Info().Timestamp().Str("name", name).Msg("Running test")
|
||||
|
||||
out, err := p.Run(
|
||||
ctx,
|
||||
runtime.WithLog(zerolog.ConsoleWriter{Out: os.Stdout}),
|
||||
@ -207,20 +223,9 @@ func (r *Runner) report(results []Result) Summary {
|
||||
|
||||
for _, res := range results {
|
||||
if res.err != nil {
|
||||
r.logger.Error().
|
||||
Timestamp().
|
||||
Err(res.err).
|
||||
Str("file", res.name).
|
||||
Dur("time", res.duration).
|
||||
Msg("Test failed")
|
||||
|
||||
failed++
|
||||
} else {
|
||||
r.logger.Info().
|
||||
Timestamp().
|
||||
Str("file", res.name).
|
||||
Dur("time", res.duration).
|
||||
Msg("Test passed")
|
||||
|
||||
passed++
|
||||
}
|
||||
|
@ -273,32 +273,32 @@ func (doc *HTMLDocument) Length() values.Int {
|
||||
return doc.element.Length()
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) GetChildNodes() core.Value {
|
||||
func (doc *HTMLDocument) GetChildNodes(ctx context.Context) core.Value {
|
||||
doc.Lock()
|
||||
defer doc.Unlock()
|
||||
|
||||
return doc.element.GetChildNodes()
|
||||
return doc.element.GetChildNodes(ctx)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) GetChildNode(idx values.Int) core.Value {
|
||||
func (doc *HTMLDocument) GetChildNode(ctx context.Context, idx values.Int) core.Value {
|
||||
doc.Lock()
|
||||
defer doc.Unlock()
|
||||
|
||||
return doc.element.GetChildNode(idx)
|
||||
return doc.element.GetChildNode(ctx, idx)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) QuerySelector(selector values.String) core.Value {
|
||||
func (doc *HTMLDocument) QuerySelector(ctx context.Context, selector values.String) core.Value {
|
||||
doc.Lock()
|
||||
defer doc.Unlock()
|
||||
|
||||
return doc.element.QuerySelector(selector)
|
||||
return doc.element.QuerySelector(ctx, selector)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) QuerySelectorAll(selector values.String) core.Value {
|
||||
func (doc *HTMLDocument) QuerySelectorAll(ctx context.Context, selector values.String) core.Value {
|
||||
doc.Lock()
|
||||
defer doc.Unlock()
|
||||
|
||||
return doc.element.QuerySelectorAll(selector)
|
||||
return doc.element.QuerySelectorAll(ctx, selector)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) DocumentElement() drivers.HTMLElement {
|
||||
@ -315,26 +315,27 @@ func (doc *HTMLDocument) GetURL() core.Value {
|
||||
return doc.url
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) SetURL(url values.String) error {
|
||||
return doc.Navigate(url, values.Int(DefaultTimeout))
|
||||
func (doc *HTMLDocument) SetURL(ctx context.Context, url values.String) error {
|
||||
return doc.Navigate(ctx, url)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) CountBySelector(selector values.String) values.Int {
|
||||
func (doc *HTMLDocument) CountBySelector(ctx context.Context, selector values.String) values.Int {
|
||||
doc.Lock()
|
||||
defer doc.Unlock()
|
||||
|
||||
return doc.element.CountBySelector(selector)
|
||||
return doc.element.CountBySelector(ctx, selector)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ExistsBySelector(selector values.String) values.Boolean {
|
||||
func (doc *HTMLDocument) ExistsBySelector(ctx context.Context, selector values.String) values.Boolean {
|
||||
doc.Lock()
|
||||
defer doc.Unlock()
|
||||
|
||||
return doc.element.ExistsBySelector(selector)
|
||||
return doc.element.ExistsBySelector(ctx, selector)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ClickBySelector(selector values.String) (values.Boolean, error) {
|
||||
func (doc *HTMLDocument) ClickBySelector(ctx context.Context, selector values.String) (values.Boolean, error) {
|
||||
res, err := eval.Eval(
|
||||
ctx,
|
||||
doc.client,
|
||||
fmt.Sprintf(`
|
||||
var el = document.querySelector(%s);
|
||||
@ -360,8 +361,9 @@ func (doc *HTMLDocument) ClickBySelector(selector values.String) (values.Boolean
|
||||
return values.False, nil
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ClickBySelectorAll(selector values.String) (values.Boolean, error) {
|
||||
func (doc *HTMLDocument) ClickBySelectorAll(ctx context.Context, selector values.String) (values.Boolean, error) {
|
||||
res, err := eval.Eval(
|
||||
ctx,
|
||||
doc.client,
|
||||
fmt.Sprintf(`
|
||||
var elements = document.querySelectorAll(%s);
|
||||
@ -389,12 +391,11 @@ func (doc *HTMLDocument) ClickBySelectorAll(selector values.String) (values.Bool
|
||||
return values.False, nil
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) InputBySelector(selector values.String, value core.Value, delay values.Int) (values.Boolean, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
func (doc *HTMLDocument) InputBySelector(ctx context.Context, selector values.String, value core.Value, delay values.Int) (values.Boolean, error) {
|
||||
valStr := value.String()
|
||||
|
||||
res, err := eval.Eval(
|
||||
ctx,
|
||||
doc.client,
|
||||
fmt.Sprintf(`
|
||||
var el = document.querySelector(%s);
|
||||
@ -423,9 +424,11 @@ func (doc *HTMLDocument) InputBySelector(selector values.String, value core.Valu
|
||||
for _, ch := range valStr {
|
||||
for _, ev := range []string{"keyDown", "keyUp"} {
|
||||
ke := input.NewDispatchKeyEventArgs(ev).SetText(string(ch))
|
||||
|
||||
if err := doc.client.Input.DispatchKeyEvent(ctx, ke); err != nil {
|
||||
return values.False, err
|
||||
}
|
||||
|
||||
time.Sleep(delayMs * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@ -433,8 +436,9 @@ func (doc *HTMLDocument) InputBySelector(selector values.String, value core.Valu
|
||||
return values.True, nil
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) SelectBySelector(selector values.String, value *values.Array) (*values.Array, error) {
|
||||
func (doc *HTMLDocument) SelectBySelector(ctx context.Context, selector values.String, value *values.Array) (*values.Array, error) {
|
||||
res, err := eval.Eval(
|
||||
ctx,
|
||||
doc.client,
|
||||
fmt.Sprintf(`
|
||||
var element = document.querySelector(%s);
|
||||
@ -479,11 +483,8 @@ func (doc *HTMLDocument) SelectBySelector(selector values.String, value *values.
|
||||
return nil, core.TypeError(types.Array, res.Type())
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) HoverBySelector(selector values.String) error {
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
err := doc.ScrollBySelector(selector)
|
||||
func (doc *HTMLDocument) HoverBySelector(ctx context.Context, selector values.String) error {
|
||||
err := doc.ScrollBySelector(ctx, selector)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@ -518,7 +519,7 @@ func (doc *HTMLDocument) HoverBySelector(selector values.String) error {
|
||||
)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForSelector(selector values.String, timeout values.Int) error {
|
||||
func (doc *HTMLDocument) WaitForSelector(ctx context.Context, selector values.String) error {
|
||||
task := events.NewEvalWaitTask(
|
||||
doc.client,
|
||||
fmt.Sprintf(`
|
||||
@ -529,16 +530,15 @@ func (doc *HTMLDocument) WaitForSelector(selector values.String, timeout values.
|
||||
// null means we need to repeat
|
||||
return null;
|
||||
`, eval.ParamString(selector.String())),
|
||||
time.Millisecond*time.Duration(timeout),
|
||||
events.DefaultPolling,
|
||||
)
|
||||
|
||||
_, err := task.Run()
|
||||
_, err := task.Run(ctx)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForClassBySelector(selector, class values.String, timeout values.Int) error {
|
||||
func (doc *HTMLDocument) WaitForClassBySelector(ctx context.Context, selector, class values.String) error {
|
||||
task := events.NewEvalWaitTask(
|
||||
doc.client,
|
||||
fmt.Sprintf(`
|
||||
@ -558,16 +558,15 @@ func (doc *HTMLDocument) WaitForClassBySelector(selector, class values.String, t
|
||||
eval.ParamString(selector.String()),
|
||||
eval.ParamString(class.String()),
|
||||
),
|
||||
time.Millisecond*time.Duration(timeout),
|
||||
events.DefaultPolling,
|
||||
)
|
||||
|
||||
_, err := task.Run()
|
||||
_, err := task.Run(ctx)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForClassBySelectorAll(selector, class values.String, timeout values.Int) error {
|
||||
func (doc *HTMLDocument) WaitForClassBySelectorAll(ctx context.Context, selector, class values.String) error {
|
||||
task := events.NewEvalWaitTask(
|
||||
doc.client,
|
||||
fmt.Sprintf(`
|
||||
@ -593,23 +592,17 @@ func (doc *HTMLDocument) WaitForClassBySelectorAll(selector, class values.String
|
||||
eval.ParamString(selector.String()),
|
||||
eval.ParamString(class.String()),
|
||||
),
|
||||
time.Millisecond*time.Duration(timeout),
|
||||
events.DefaultPolling,
|
||||
)
|
||||
|
||||
_, err := task.Run()
|
||||
_, err := task.Run(ctx)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForNavigation(timeout values.Int) error {
|
||||
// do not wait
|
||||
if timeout == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForNavigation(ctx context.Context) error {
|
||||
onEvent := make(chan struct{})
|
||||
listener := func(_ interface{}) {
|
||||
listener := func(_ context.Context, _ interface{}) {
|
||||
close(onEvent)
|
||||
}
|
||||
|
||||
@ -620,17 +613,16 @@ func (doc *HTMLDocument) WaitForNavigation(timeout values.Int) error {
|
||||
select {
|
||||
case <-onEvent:
|
||||
return nil
|
||||
case <-time.After(time.Millisecond * time.Duration(timeout)):
|
||||
case <-ctx.Done():
|
||||
return core.ErrTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) Navigate(url values.String, timeout values.Int) error {
|
||||
func (doc *HTMLDocument) Navigate(ctx context.Context, url values.String) error {
|
||||
if url == "" {
|
||||
url = BlankPageURL
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
repl, err := doc.client.Page.Navigate(ctx, page.NewNavigateArgs(url.String()))
|
||||
|
||||
if err != nil {
|
||||
@ -641,11 +633,10 @@ func (doc *HTMLDocument) Navigate(url values.String, timeout values.Int) error {
|
||||
return errors.New(*repl.ErrorText)
|
||||
}
|
||||
|
||||
return doc.WaitForNavigation(timeout)
|
||||
return doc.WaitForNavigation(ctx)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) NavigateBack(skip values.Int, timeout values.Int) (values.Boolean, error) {
|
||||
ctx := context.Background()
|
||||
func (doc *HTMLDocument) NavigateBack(ctx context.Context, skip values.Int) (values.Boolean, error) {
|
||||
history, err := doc.client.Page.GetNavigationHistory(ctx)
|
||||
|
||||
if err != nil {
|
||||
@ -675,7 +666,7 @@ func (doc *HTMLDocument) NavigateBack(skip values.Int, timeout values.Int) (valu
|
||||
return values.False, err
|
||||
}
|
||||
|
||||
err = doc.WaitForNavigation(timeout)
|
||||
err = doc.WaitForNavigation(ctx)
|
||||
|
||||
if err != nil {
|
||||
return values.False, err
|
||||
@ -684,8 +675,7 @@ func (doc *HTMLDocument) NavigateBack(skip values.Int, timeout values.Int) (valu
|
||||
return values.True, nil
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) NavigateForward(skip values.Int, timeout values.Int) (values.Boolean, error) {
|
||||
ctx := context.Background()
|
||||
func (doc *HTMLDocument) NavigateForward(ctx context.Context, skip values.Int) (values.Boolean, error) {
|
||||
history, err := doc.client.Page.GetNavigationHistory(ctx)
|
||||
|
||||
if err != nil {
|
||||
@ -718,7 +708,7 @@ func (doc *HTMLDocument) NavigateForward(skip values.Int, timeout values.Int) (v
|
||||
return values.False, err
|
||||
}
|
||||
|
||||
err = doc.WaitForNavigation(timeout)
|
||||
err = doc.WaitForNavigation(ctx)
|
||||
|
||||
if err != nil {
|
||||
return values.False, err
|
||||
@ -727,9 +717,7 @@ func (doc *HTMLDocument) NavigateForward(skip values.Int, timeout values.Int) (v
|
||||
return values.True, nil
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) PrintToPDF(params drivers.PDFParams) (values.Binary, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
func (doc *HTMLDocument) PrintToPDF(ctx context.Context, params drivers.PDFParams) (values.Binary, error) {
|
||||
args := page.NewPrintToPDFArgs()
|
||||
args.
|
||||
SetLandscape(bool(params.Landscape)).
|
||||
@ -787,8 +775,7 @@ func (doc *HTMLDocument) PrintToPDF(params drivers.PDFParams) (values.Binary, er
|
||||
return values.NewBinary(reply.Data), nil
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) CaptureScreenshot(params drivers.ScreenshotParams) (values.Binary, error) {
|
||||
ctx := context.Background()
|
||||
func (doc *HTMLDocument) CaptureScreenshot(ctx context.Context, params drivers.ScreenshotParams) (values.Binary, error) {
|
||||
metrics, err := doc.client.Page.GetLayoutMetrics(ctx)
|
||||
|
||||
if params.Format == drivers.ScreenshotFormatJPEG && params.Quality < 0 && params.Quality > 100 {
|
||||
@ -836,8 +823,8 @@ func (doc *HTMLDocument) CaptureScreenshot(params drivers.ScreenshotParams) (val
|
||||
return values.NewBinary(reply.Data), nil
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ScrollTop() error {
|
||||
_, err := eval.Eval(doc.client, `
|
||||
func (doc *HTMLDocument) ScrollTop(ctx context.Context) error {
|
||||
_, err := eval.Eval(ctx, doc.client, `
|
||||
window.scrollTo({
|
||||
left: 0,
|
||||
top: 0,
|
||||
@ -848,8 +835,8 @@ func (doc *HTMLDocument) ScrollTop() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ScrollBottom() error {
|
||||
_, err := eval.Eval(doc.client, `
|
||||
func (doc *HTMLDocument) ScrollBottom(ctx context.Context) error {
|
||||
_, err := eval.Eval(ctx, doc.client, `
|
||||
window.scrollTo({
|
||||
left: 0,
|
||||
top: window.document.body.scrollHeight,
|
||||
@ -860,8 +847,8 @@ func (doc *HTMLDocument) ScrollBottom() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ScrollBySelector(selector values.String) error {
|
||||
_, err := eval.Eval(doc.client, fmt.Sprintf(`
|
||||
func (doc *HTMLDocument) ScrollBySelector(ctx context.Context, selector values.String) error {
|
||||
_, err := eval.Eval(ctx, doc.client, fmt.Sprintf(`
|
||||
var el = document.querySelector(%s);
|
||||
if (el == null) {
|
||||
throw new Error("element not found");
|
||||
@ -876,13 +863,10 @@ func (doc *HTMLDocument) ScrollBySelector(selector values.String) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) handlePageLoad(_ interface{}) {
|
||||
func (doc *HTMLDocument) handlePageLoad(ctx context.Context, _ interface{}) {
|
||||
doc.Lock()
|
||||
defer doc.Unlock()
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
node, err := getRootElement(ctx, doc.client)
|
||||
|
||||
if err != nil {
|
||||
@ -924,7 +908,7 @@ func (doc *HTMLDocument) handlePageLoad(_ interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) handleError(val interface{}) {
|
||||
func (doc *HTMLDocument) handleError(_ context.Context, val interface{}) {
|
||||
err, ok := val.(error)
|
||||
|
||||
if !ok {
|
||||
|
@ -25,8 +25,6 @@ import (
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const DefaultTimeout = time.Second * 30
|
||||
|
||||
var emptyNodeID = dom.NodeID(0)
|
||||
var emptyBackendID = dom.BackendNodeID(0)
|
||||
|
||||
@ -201,7 +199,7 @@ func (el *HTMLElement) Type() core.Type {
|
||||
}
|
||||
|
||||
func (el *HTMLElement) MarshalJSON() ([]byte, error) {
|
||||
val, err := el.innerText.Read()
|
||||
val, err := el.innerText.Read(context.Background())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -211,7 +209,7 @@ func (el *HTMLElement) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (el *HTMLElement) String() string {
|
||||
return el.InnerHTML().String()
|
||||
return el.InnerHTML(context.Background()).String()
|
||||
}
|
||||
|
||||
func (el *HTMLElement) Compare(other core.Value) int64 {
|
||||
@ -219,7 +217,9 @@ func (el *HTMLElement) Compare(other core.Value) int64 {
|
||||
case drivers.HTMLElementType:
|
||||
other := other.(drivers.HTMLElement)
|
||||
|
||||
return el.InnerHTML().Compare(other.InnerHTML())
|
||||
ctx := context.Background()
|
||||
|
||||
return el.InnerHTML(ctx).Compare(other.InnerHTML(ctx))
|
||||
default:
|
||||
return drivers.Compare(el.Type(), other.Type())
|
||||
}
|
||||
@ -258,14 +258,11 @@ func (el *HTMLElement) SetIn(ctx context.Context, path []core.Value, value core.
|
||||
return common.SetInElement(ctx, el, path, value)
|
||||
}
|
||||
|
||||
func (el *HTMLElement) GetValue() core.Value {
|
||||
func (el *HTMLElement) GetValue(ctx context.Context) core.Value {
|
||||
if !el.IsConnected() {
|
||||
return el.value
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
val, err := eval.Property(ctx, el.client, el.id.objectID, "value")
|
||||
|
||||
if err != nil {
|
||||
@ -279,15 +276,12 @@ func (el *HTMLElement) GetValue() core.Value {
|
||||
return val
|
||||
}
|
||||
|
||||
func (el *HTMLElement) SetValue(value core.Value) error {
|
||||
func (el *HTMLElement) SetValue(ctx context.Context, value core.Value) error {
|
||||
if !el.IsConnected() {
|
||||
// TODO: Return an error
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
return el.client.DOM.SetNodeValue(ctx, dom.NewSetNodeValueArgs(el.id.nodeID, value.String()))
|
||||
}
|
||||
|
||||
@ -303,8 +297,8 @@ func (el *HTMLElement) Length() values.Int {
|
||||
return values.NewInt(len(el.children))
|
||||
}
|
||||
|
||||
func (el *HTMLElement) GetAttributes() core.Value {
|
||||
val, err := el.attributes.Read()
|
||||
func (el *HTMLElement) GetAttributes(ctx context.Context) core.Value {
|
||||
val, err := el.attributes.Read(ctx)
|
||||
|
||||
if err != nil {
|
||||
return values.None
|
||||
@ -314,8 +308,8 @@ func (el *HTMLElement) GetAttributes() core.Value {
|
||||
return val.Copy()
|
||||
}
|
||||
|
||||
func (el *HTMLElement) GetAttribute(name values.String) core.Value {
|
||||
attrs, err := el.attributes.Read()
|
||||
func (el *HTMLElement) GetAttribute(ctx context.Context, name values.String) core.Value {
|
||||
attrs, err := el.attributes.Read(ctx)
|
||||
|
||||
if err != nil {
|
||||
return values.None
|
||||
@ -330,15 +324,15 @@ func (el *HTMLElement) GetAttribute(name values.String) core.Value {
|
||||
return val
|
||||
}
|
||||
|
||||
func (el *HTMLElement) SetAttribute(name, value values.String) error {
|
||||
func (el *HTMLElement) SetAttribute(ctx context.Context, name, value values.String) error {
|
||||
return el.client.DOM.SetAttributeValue(
|
||||
context.Background(),
|
||||
ctx,
|
||||
dom.NewSetAttributeValueArgs(el.id.nodeID, string(name), string(value)),
|
||||
)
|
||||
}
|
||||
|
||||
func (el *HTMLElement) GetChildNodes() core.Value {
|
||||
val, err := el.loadedChildren.Read()
|
||||
func (el *HTMLElement) GetChildNodes(ctx context.Context) core.Value {
|
||||
val, err := el.loadedChildren.Read(ctx)
|
||||
|
||||
if err != nil {
|
||||
return values.NewArray(0)
|
||||
@ -347,9 +341,8 @@ func (el *HTMLElement) GetChildNodes() core.Value {
|
||||
return val
|
||||
}
|
||||
|
||||
func (el *HTMLElement) GetChildNode(idx values.Int) core.Value {
|
||||
// TODO: Add lazy loading
|
||||
val, err := el.loadedChildren.Read()
|
||||
func (el *HTMLElement) GetChildNode(ctx context.Context, idx values.Int) core.Value {
|
||||
val, err := el.loadedChildren.Read(ctx)
|
||||
|
||||
if err != nil {
|
||||
return values.None
|
||||
@ -358,14 +351,11 @@ func (el *HTMLElement) GetChildNode(idx values.Int) core.Value {
|
||||
return val.(*values.Array).Get(idx)
|
||||
}
|
||||
|
||||
func (el *HTMLElement) QuerySelector(selector values.String) core.Value {
|
||||
func (el *HTMLElement) QuerySelector(ctx context.Context, selector values.String) core.Value {
|
||||
if !el.IsConnected() {
|
||||
return values.None
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
// TODO: Can we use RemoteObjectID or BackendID instead of NodeId?
|
||||
selectorArgs := dom.NewQuerySelectorArgs(el.id.nodeID, selector.String())
|
||||
found, err := el.client.DOM.QuerySelector(ctx, selectorArgs)
|
||||
@ -399,14 +389,11 @@ func (el *HTMLElement) QuerySelector(selector values.String) core.Value {
|
||||
return res
|
||||
}
|
||||
|
||||
func (el *HTMLElement) QuerySelectorAll(selector values.String) core.Value {
|
||||
func (el *HTMLElement) QuerySelectorAll(ctx context.Context, selector values.String) core.Value {
|
||||
if !el.IsConnected() {
|
||||
return values.NewArray(0)
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
// TODO: Can we use RemoteObjectID or BackendID instead of NodeId?
|
||||
selectorArgs := dom.NewQuerySelectorAllArgs(el.id.nodeID, selector.String())
|
||||
res, err := el.client.DOM.QuerySelectorAll(ctx, selectorArgs)
|
||||
@ -455,8 +442,8 @@ func (el *HTMLElement) QuerySelectorAll(selector values.String) core.Value {
|
||||
return arr
|
||||
}
|
||||
|
||||
func (el *HTMLElement) InnerText() values.String {
|
||||
val, err := el.innerText.Read()
|
||||
func (el *HTMLElement) InnerText(ctx context.Context) values.String {
|
||||
val, err := el.innerText.Read(ctx)
|
||||
|
||||
if err != nil {
|
||||
return values.EmptyString
|
||||
@ -469,14 +456,11 @@ func (el *HTMLElement) InnerText() values.String {
|
||||
return val.(values.String)
|
||||
}
|
||||
|
||||
func (el *HTMLElement) InnerTextBySelector(selector values.String) values.String {
|
||||
func (el *HTMLElement) InnerTextBySelector(ctx context.Context, selector values.String) values.String {
|
||||
if !el.IsConnected() {
|
||||
return values.EmptyString
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
// TODO: Can we use RemoteObjectID or BackendID instead of NodeId?
|
||||
found, err := el.client.DOM.QuerySelector(ctx, dom.NewQuerySelectorArgs(el.id.nodeID, selector.String()))
|
||||
|
||||
@ -534,10 +518,7 @@ func (el *HTMLElement) InnerTextBySelector(selector values.String) values.String
|
||||
return values.NewString(text.String())
|
||||
}
|
||||
|
||||
func (el *HTMLElement) InnerTextBySelectorAll(selector values.String) *values.Array {
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
func (el *HTMLElement) InnerTextBySelectorAll(ctx context.Context, selector values.String) *values.Array {
|
||||
// TODO: Can we use RemoteObjectID or BackendID instead of NodeId?
|
||||
res, err := el.client.DOM.QuerySelectorAll(ctx, dom.NewQuerySelectorAllArgs(el.id.nodeID, selector.String()))
|
||||
|
||||
@ -595,21 +576,18 @@ func (el *HTMLElement) InnerTextBySelectorAll(selector values.String) *values.Ar
|
||||
return arr
|
||||
}
|
||||
|
||||
func (el *HTMLElement) InnerHTML() values.String {
|
||||
func (el *HTMLElement) InnerHTML(_ context.Context) values.String {
|
||||
el.mu.Lock()
|
||||
defer el.mu.Unlock()
|
||||
|
||||
return el.innerHTML
|
||||
}
|
||||
|
||||
func (el *HTMLElement) InnerHTMLBySelector(selector values.String) values.String {
|
||||
func (el *HTMLElement) InnerHTMLBySelector(ctx context.Context, selector values.String) values.String {
|
||||
if !el.IsConnected() {
|
||||
return values.EmptyString
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
// TODO: Can we use RemoteObjectID or BackendID instead of NodeId?
|
||||
found, err := el.client.DOM.QuerySelector(ctx, dom.NewQuerySelectorArgs(el.id.nodeID, selector.String()))
|
||||
|
||||
@ -636,10 +614,7 @@ func (el *HTMLElement) InnerHTMLBySelector(selector values.String) values.String
|
||||
return text
|
||||
}
|
||||
|
||||
func (el *HTMLElement) InnerHTMLBySelectorAll(selector values.String) *values.Array {
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
func (el *HTMLElement) InnerHTMLBySelectorAll(ctx context.Context, selector values.String) *values.Array {
|
||||
// TODO: Can we use RemoteObjectID or BackendID instead of NodeId?
|
||||
selectorArgs := dom.NewQuerySelectorAllArgs(el.id.nodeID, selector.String())
|
||||
res, err := el.client.DOM.QuerySelectorAll(ctx, selectorArgs)
|
||||
@ -674,14 +649,11 @@ func (el *HTMLElement) InnerHTMLBySelectorAll(selector values.String) *values.Ar
|
||||
return arr
|
||||
}
|
||||
|
||||
func (el *HTMLElement) CountBySelector(selector values.String) values.Int {
|
||||
func (el *HTMLElement) CountBySelector(ctx context.Context, selector values.String) values.Int {
|
||||
if !el.IsConnected() {
|
||||
return values.ZeroInt
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
// TODO: Can we use RemoteObjectID or BackendID instead of NodeId?
|
||||
selectorArgs := dom.NewQuerySelectorAllArgs(el.id.nodeID, selector.String())
|
||||
res, err := el.client.DOM.QuerySelectorAll(ctx, selectorArgs)
|
||||
@ -697,14 +669,11 @@ func (el *HTMLElement) CountBySelector(selector values.String) values.Int {
|
||||
return values.NewInt(len(res.NodeIDs))
|
||||
}
|
||||
|
||||
func (el *HTMLElement) ExistsBySelector(selector values.String) values.Boolean {
|
||||
func (el *HTMLElement) ExistsBySelector(ctx context.Context, selector values.String) values.Boolean {
|
||||
if !el.IsConnected() {
|
||||
return values.False
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
// TODO: Can we use RemoteObjectID or BackendID instead of NodeId?
|
||||
selectorArgs := dom.NewQuerySelectorArgs(el.id.nodeID, selector.String())
|
||||
res, err := el.client.DOM.QuerySelector(ctx, selectorArgs)
|
||||
@ -724,10 +693,10 @@ func (el *HTMLElement) ExistsBySelector(selector values.String) values.Boolean {
|
||||
return values.True
|
||||
}
|
||||
|
||||
func (el *HTMLElement) WaitForClass(class values.String, timeout values.Int) error {
|
||||
func (el *HTMLElement) WaitForClass(ctx context.Context, class values.String) error {
|
||||
task := events.NewWaitTask(
|
||||
func() (core.Value, error) {
|
||||
current := el.GetAttribute("class")
|
||||
func(ctx2 context.Context) (core.Value, error) {
|
||||
current := el.GetAttribute(ctx2, "class")
|
||||
|
||||
if current.Type() != types.String {
|
||||
return values.None, nil
|
||||
@ -745,27 +714,19 @@ func (el *HTMLElement) WaitForClass(class values.String, timeout values.Int) err
|
||||
|
||||
return values.None, nil
|
||||
},
|
||||
time.Millisecond*time.Duration(timeout),
|
||||
events.DefaultPolling,
|
||||
)
|
||||
|
||||
_, err := task.Run()
|
||||
_, err := task.Run(ctx)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (el *HTMLElement) Click() (values.Boolean, error) {
|
||||
ctx, cancel := contextWithTimeout()
|
||||
|
||||
defer cancel()
|
||||
|
||||
func (el *HTMLElement) Click(ctx context.Context) (values.Boolean, error) {
|
||||
return events.DispatchEvent(ctx, el.client, el.id.objectID, "click")
|
||||
}
|
||||
|
||||
func (el *HTMLElement) Input(value core.Value, delay values.Int) error {
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
func (el *HTMLElement) Input(ctx context.Context, value core.Value, delay values.Int) error {
|
||||
if err := el.client.DOM.Focus(ctx, dom.NewFocusArgs().SetObjectID(el.id.objectID)); err != nil {
|
||||
el.logError(err).Msg("failed to focus")
|
||||
|
||||
@ -795,7 +756,7 @@ func (el *HTMLElement) Input(value core.Value, delay values.Int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (el *HTMLElement) Select(value *values.Array) (*values.Array, error) {
|
||||
func (el *HTMLElement) Select(ctx context.Context, value *values.Array) (*values.Array, error) {
|
||||
var attrID = "data-ferret-select"
|
||||
|
||||
if el.NodeName() != "SELECT" {
|
||||
@ -808,9 +769,6 @@ func (el *HTMLElement) Select(value *values.Array) (*values.Array, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
err = el.client.DOM.SetAttributeValue(ctx, dom.NewSetAttributeValueArgs(el.id.nodeID, attrID, id.String()))
|
||||
|
||||
if err != nil {
|
||||
@ -818,6 +776,7 @@ func (el *HTMLElement) Select(value *values.Array) (*values.Array, error) {
|
||||
}
|
||||
|
||||
res, err := eval.Eval(
|
||||
ctx,
|
||||
el.client,
|
||||
fmt.Sprintf(`
|
||||
var el = document.querySelector('[%s="%s"]');
|
||||
@ -865,7 +824,7 @@ func (el *HTMLElement) Select(value *values.Array) (*values.Array, error) {
|
||||
return nil, core.TypeError(types.Array, res.Type())
|
||||
}
|
||||
|
||||
func (el *HTMLElement) ScrollIntoView() error {
|
||||
func (el *HTMLElement) ScrollIntoView(ctx context.Context) error {
|
||||
var attrID = "data-ferret-scroll"
|
||||
|
||||
id, err := uuid.NewV4()
|
||||
@ -874,45 +833,43 @@ func (el *HTMLElement) ScrollIntoView() error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
err = el.client.DOM.SetAttributeValue(ctx, dom.NewSetAttributeValueArgs(el.id.nodeID, attrID, id.String()))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = eval.Eval(el.client, fmt.Sprintf(`
|
||||
var el = document.querySelector('[%s="%s"]');
|
||||
if (el == null) {
|
||||
throw new Error('element not found');
|
||||
}
|
||||
el.scrollIntoView({
|
||||
behavior: 'instant',
|
||||
inline: 'center',
|
||||
block: 'center'
|
||||
});
|
||||
`,
|
||||
attrID,
|
||||
id.String(),
|
||||
), false, false)
|
||||
_, err = eval.Eval(
|
||||
ctx,
|
||||
el.client,
|
||||
fmt.Sprintf(`
|
||||
var el = document.querySelector('[%s="%s"]');
|
||||
if (el == null) {
|
||||
throw new Error('element not found');
|
||||
}
|
||||
|
||||
el.scrollIntoView({
|
||||
behavior: 'instant',
|
||||
inline: 'center',
|
||||
block: 'center'
|
||||
});
|
||||
`,
|
||||
attrID,
|
||||
id.String(),
|
||||
), false, false)
|
||||
|
||||
el.client.DOM.RemoveAttribute(ctx, dom.NewRemoveAttributeArgs(el.id.nodeID, attrID))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (el *HTMLElement) Hover() error {
|
||||
err := el.ScrollIntoView()
|
||||
func (el *HTMLElement) Hover(ctx context.Context) error {
|
||||
err := el.ScrollIntoView(ctx)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
q, err := getClickablePoint(ctx, el.client, el.id)
|
||||
|
||||
if err != nil {
|
||||
@ -932,11 +889,8 @@ func (el *HTMLElement) IsConnected() values.Boolean {
|
||||
return el.connected
|
||||
}
|
||||
|
||||
func (el *HTMLElement) loadInnerText() (core.Value, error) {
|
||||
func (el *HTMLElement) loadInnerText(ctx context.Context) (core.Value, error) {
|
||||
if el.IsConnected() {
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
text, err := loadInnerText(ctx, el.client, el.id)
|
||||
|
||||
if err == nil {
|
||||
@ -948,7 +902,7 @@ func (el *HTMLElement) loadInnerText() (core.Value, error) {
|
||||
// and just parse cached innerHTML
|
||||
}
|
||||
|
||||
h := el.InnerHTML()
|
||||
h := el.InnerHTML(ctx)
|
||||
|
||||
if h == values.EmptyString {
|
||||
return h, nil
|
||||
@ -965,18 +919,15 @@ func (el *HTMLElement) loadInnerText() (core.Value, error) {
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func (el *HTMLElement) loadAttrs() (core.Value, error) {
|
||||
func (el *HTMLElement) loadAttrs(_ context.Context) (core.Value, error) {
|
||||
return parseAttrs(el.rawAttrs), nil
|
||||
}
|
||||
|
||||
func (el *HTMLElement) loadChildren() (core.Value, error) {
|
||||
func (el *HTMLElement) loadChildren(ctx context.Context) (core.Value, error) {
|
||||
if !el.IsConnected() {
|
||||
return values.NewArray(0), nil
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
loaded := values.NewArray(len(el.children))
|
||||
|
||||
for _, childID := range el.children {
|
||||
@ -1001,11 +952,11 @@ func (el *HTMLElement) loadChildren() (core.Value, error) {
|
||||
return loaded, nil
|
||||
}
|
||||
|
||||
func (el *HTMLElement) handlePageReload(_ interface{}) {
|
||||
func (el *HTMLElement) handlePageReload(_ context.Context, _ interface{}) {
|
||||
el.Close()
|
||||
}
|
||||
|
||||
func (el *HTMLElement) handleAttrModified(message interface{}) {
|
||||
func (el *HTMLElement) handleAttrModified(ctx context.Context, message interface{}) {
|
||||
reply, ok := message.(*dom.AttributeModifiedReply)
|
||||
|
||||
// well....
|
||||
@ -1018,7 +969,7 @@ func (el *HTMLElement) handleAttrModified(message interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
el.attributes.Write(func(v core.Value, err error) {
|
||||
el.attributes.Write(ctx, func(v core.Value, err error) {
|
||||
if err != nil {
|
||||
el.logError(err).Msg("failed to update element")
|
||||
|
||||
@ -1035,7 +986,7 @@ func (el *HTMLElement) handleAttrModified(message interface{}) {
|
||||
})
|
||||
}
|
||||
|
||||
func (el *HTMLElement) handleAttrRemoved(message interface{}) {
|
||||
func (el *HTMLElement) handleAttrRemoved(ctx context.Context, message interface{}) {
|
||||
reply, ok := message.(*dom.AttributeRemovedReply)
|
||||
|
||||
// well....
|
||||
@ -1054,7 +1005,7 @@ func (el *HTMLElement) handleAttrRemoved(message interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
el.attributes.Write(func(v core.Value, err error) {
|
||||
el.attributes.Write(ctx, func(v core.Value, err error) {
|
||||
if err != nil {
|
||||
el.logError(err).Msg("failed to update element")
|
||||
|
||||
@ -1071,7 +1022,7 @@ func (el *HTMLElement) handleAttrRemoved(message interface{}) {
|
||||
})
|
||||
}
|
||||
|
||||
func (el *HTMLElement) handleChildrenCountChanged(message interface{}) {
|
||||
func (el *HTMLElement) handleChildrenCountChanged(ctx context.Context, message interface{}) {
|
||||
reply, ok := message.(*dom.ChildNodeCountUpdatedReply)
|
||||
|
||||
if !ok {
|
||||
@ -1082,9 +1033,6 @@ func (el *HTMLElement) handleChildrenCountChanged(message interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
node, err := el.client.DOM.DescribeNode(
|
||||
ctx,
|
||||
dom.NewDescribeNodeArgs().SetObjectID(el.id.objectID),
|
||||
@ -1102,7 +1050,7 @@ func (el *HTMLElement) handleChildrenCountChanged(message interface{}) {
|
||||
el.children = createChildrenArray(node.Node.Children)
|
||||
}
|
||||
|
||||
func (el *HTMLElement) handleChildInserted(message interface{}) {
|
||||
func (el *HTMLElement) handleChildInserted(ctx context.Context, message interface{}) {
|
||||
reply, ok := message.(*dom.ChildNodeInsertedReply)
|
||||
|
||||
if !ok {
|
||||
@ -1143,10 +1091,7 @@ func (el *HTMLElement) handleChildInserted(message interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
el.loadedChildren.Write(func(v core.Value, err error) {
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
el.loadedChildren.Write(ctx, func(v core.Value, err error) {
|
||||
loadedArr := v.(*values.Array)
|
||||
loadedEl, err := LoadElement(ctx, el.logger, el.client, el.events, nextID, emptyBackendID)
|
||||
|
||||
@ -1171,7 +1116,7 @@ func (el *HTMLElement) handleChildInserted(message interface{}) {
|
||||
})
|
||||
}
|
||||
|
||||
func (el *HTMLElement) handleChildRemoved(message interface{}) {
|
||||
func (el *HTMLElement) handleChildRemoved(ctx context.Context, message interface{}) {
|
||||
reply, ok := message.(*dom.ChildNodeRemovedReply)
|
||||
|
||||
if !ok {
|
||||
@ -1206,7 +1151,7 @@ func (el *HTMLElement) handleChildRemoved(message interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
el.loadedChildren.Write(func(v core.Value, err error) {
|
||||
el.loadedChildren.Write(ctx, func(v core.Value, err error) {
|
||||
if err != nil {
|
||||
el.logger.Error().
|
||||
Timestamp().
|
||||
@ -1217,9 +1162,6 @@ func (el *HTMLElement) handleChildRemoved(message interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := contextWithTimeout()
|
||||
defer cancel()
|
||||
|
||||
loadedArr := v.(*values.Array)
|
||||
loadedArr.RemoveAt(values.NewInt(targetIDx))
|
||||
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/mafredri/cdp"
|
||||
@ -18,13 +19,13 @@ func ParamString(param string) string {
|
||||
return "`" + param + "`"
|
||||
}
|
||||
|
||||
func Eval(client *cdp.Client, exp string, ret bool, async bool) (core.Value, error) {
|
||||
func Eval(ctx context.Context, client *cdp.Client, exp string, ret bool, async bool) (core.Value, error) {
|
||||
args := runtime.
|
||||
NewEvaluateArgs(PrepareEval(exp)).
|
||||
SetReturnByValue(ret).
|
||||
SetAwaitPromise(async)
|
||||
|
||||
out, err := client.Runtime.Evaluate(context.Background(), args)
|
||||
out, err := client.Runtime.Evaluate(ctx, args)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
|
@ -2,17 +2,19 @@ package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/drivers"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/mafredri/cdp/protocol/dom"
|
||||
"github.com/mafredri/cdp/protocol/page"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
Event int
|
||||
|
||||
EventListener func(message interface{})
|
||||
EventListener func(ctx context.Context, message interface{})
|
||||
|
||||
EventBroker struct {
|
||||
mu sync.Mutex
|
||||
@ -275,7 +277,11 @@ func (broker *EventBroker) emit(ctx context.Context, event Event, message interf
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
listener(message)
|
||||
ctx2, fn := drivers.WithDefaultTimeout(ctx)
|
||||
|
||||
listener(ctx2, message)
|
||||
|
||||
fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package events_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/drivers/cdp/events"
|
||||
"github.com/mafredri/cdp/protocol/dom"
|
||||
"github.com/mafredri/cdp/protocol/page"
|
||||
@ -198,7 +199,7 @@ func TestEventBroker(t *testing.T) {
|
||||
b := NewTestEventBroker()
|
||||
|
||||
StressTest(func() error {
|
||||
b.AddEventListener(events.EventLoad, func(message interface{}) {})
|
||||
b.AddEventListener(events.EventLoad, func(ctx context.Context, message interface{}) {})
|
||||
|
||||
return nil
|
||||
}, 500)
|
||||
@ -210,7 +211,7 @@ func TestEventBroker(t *testing.T) {
|
||||
defer b.Stop()
|
||||
|
||||
StressTest(func() error {
|
||||
b.AddEventListener(events.EventLoad, func(message interface{}) {})
|
||||
b.AddEventListener(events.EventLoad, func(ctx context.Context, message interface{}) {})
|
||||
|
||||
return nil
|
||||
}, 500)
|
||||
@ -222,7 +223,7 @@ func TestEventBroker(t *testing.T) {
|
||||
b := NewTestEventBroker()
|
||||
|
||||
StressTest(func() error {
|
||||
listener := func(message interface{}) {}
|
||||
listener := func(ctx context.Context, message interface{}) {}
|
||||
|
||||
b.AddEventListener(events.EventLoad, listener)
|
||||
b.RemoveEventListener(events.EventLoad, listener)
|
||||
@ -239,7 +240,7 @@ func TestEventBroker(t *testing.T) {
|
||||
defer b.Stop()
|
||||
|
||||
StressTest(func() error {
|
||||
listener := func(message interface{}) {}
|
||||
listener := func(ctx context.Context, message interface{}) {}
|
||||
|
||||
b.AddEventListener(events.EventLoad, listener)
|
||||
|
||||
@ -267,7 +268,7 @@ func TestEventBroker(t *testing.T) {
|
||||
|
||||
var listener events.EventListener
|
||||
|
||||
listener = func(message interface{}) {
|
||||
listener = func(ctx context.Context, message interface{}) {
|
||||
counter += 1
|
||||
|
||||
b.RemoveEventListener(events.EventLoad, listener)
|
||||
@ -296,7 +297,7 @@ func TestEventBroker(t *testing.T) {
|
||||
|
||||
var counter int64
|
||||
|
||||
b.AddEventListener(events.EventLoad, func(message interface{}) {
|
||||
b.AddEventListener(events.EventLoad, func(ctx context.Context, message interface{}) {
|
||||
atomic.AddInt64(&counter, 1)
|
||||
b.Stop()
|
||||
})
|
||||
|
@ -1,6 +1,7 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/drivers/cdp/eval"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
@ -9,10 +10,10 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
Function func() (core.Value, error)
|
||||
Function func(ctx context.Context) (core.Value, error)
|
||||
|
||||
WaitTask struct {
|
||||
fun Function
|
||||
timeout time.Duration
|
||||
polling time.Duration
|
||||
}
|
||||
)
|
||||
@ -21,39 +22,31 @@ const DefaultPolling = time.Millisecond * time.Duration(200)
|
||||
|
||||
func NewWaitTask(
|
||||
fun Function,
|
||||
timeout time.Duration,
|
||||
polling time.Duration,
|
||||
) *WaitTask {
|
||||
return &WaitTask{
|
||||
fun,
|
||||
timeout,
|
||||
polling,
|
||||
}
|
||||
}
|
||||
|
||||
func (task *WaitTask) Run() (core.Value, error) {
|
||||
timer := time.NewTimer(task.timeout)
|
||||
|
||||
func (task *WaitTask) Run(ctx context.Context) (core.Value, error) {
|
||||
for {
|
||||
select {
|
||||
case <-timer.C:
|
||||
case <-ctx.Done():
|
||||
return values.None, core.ErrTimeout
|
||||
default:
|
||||
out, err := task.fun()
|
||||
out, err := task.fun(ctx)
|
||||
|
||||
// expression failed
|
||||
// terminating
|
||||
if err != nil {
|
||||
timer.Stop()
|
||||
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
// output is not empty
|
||||
// terminating
|
||||
if out != values.None {
|
||||
timer.Stop()
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@ -66,19 +59,18 @@ func (task *WaitTask) Run() (core.Value, error) {
|
||||
func NewEvalWaitTask(
|
||||
client *cdp.Client,
|
||||
predicate string,
|
||||
timeout time.Duration,
|
||||
polling time.Duration,
|
||||
) *WaitTask {
|
||||
return NewWaitTask(
|
||||
func() (core.Value, error) {
|
||||
func(ctx context.Context) (core.Value, error) {
|
||||
return eval.Eval(
|
||||
ctx,
|
||||
client,
|
||||
predicate,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
},
|
||||
timeout,
|
||||
polling,
|
||||
)
|
||||
}
|
||||
|
@ -287,10 +287,6 @@ func createChildrenArray(nodes []dom.Node) []*HTMLElementIdentity {
|
||||
return children
|
||||
}
|
||||
|
||||
func contextWithTimeout() (context.Context, context.CancelFunc) {
|
||||
return context.WithTimeout(context.Background(), DefaultTimeout)
|
||||
}
|
||||
|
||||
func waitForLoadEvent(ctx context.Context, client *cdp.Client) error {
|
||||
loadEventFired, err := client.Page.LoadEventFired(ctx)
|
||||
|
||||
|
@ -23,9 +23,9 @@ func GetInDocument(ctx context.Context, doc drivers.HTMLDocument, path []core.Va
|
||||
case "url", "URL":
|
||||
return doc.GetURL(), nil
|
||||
case "body":
|
||||
return doc.QuerySelector("body"), nil
|
||||
return doc.QuerySelector(ctx, "body"), nil
|
||||
case "head":
|
||||
return doc.QuerySelector("head"), nil
|
||||
return doc.QuerySelector(ctx, "head"), nil
|
||||
default:
|
||||
return GetInNode(ctx, doc.DocumentElement(), path)
|
||||
}
|
||||
@ -46,13 +46,13 @@ func GetInElement(ctx context.Context, el drivers.HTMLElement, path []core.Value
|
||||
|
||||
switch segment {
|
||||
case "innerText":
|
||||
return el.InnerText(), nil
|
||||
return el.InnerText(ctx), nil
|
||||
case "innerHTML":
|
||||
return el.InnerHTML(), nil
|
||||
return el.InnerHTML(ctx), nil
|
||||
case "value":
|
||||
return el.GetValue(), nil
|
||||
return el.GetValue(ctx), nil
|
||||
case "attributes":
|
||||
return el.GetAttributes(), nil
|
||||
return el.GetAttributes(ctx), nil
|
||||
default:
|
||||
return GetInNode(ctx, el, path)
|
||||
}
|
||||
@ -74,7 +74,7 @@ func GetInNode(ctx context.Context, node drivers.HTMLNode, path []core.Value) (c
|
||||
if nt == drivers.HTMLElementType || nt == drivers.HTMLDocumentType {
|
||||
re := node.(drivers.HTMLNode)
|
||||
|
||||
return re.GetChildNode(segment.(values.Int)), nil
|
||||
return re.GetChildNode(ctx, segment.(values.Int)), nil
|
||||
}
|
||||
|
||||
return values.GetIn(ctx, node, path[0:])
|
||||
@ -89,7 +89,7 @@ func GetInNode(ctx context.Context, node drivers.HTMLNode, path []core.Value) (c
|
||||
case "nodeName":
|
||||
return node.NodeName(), nil
|
||||
case "children":
|
||||
return node.GetChildNodes(), nil
|
||||
return node.GetChildNodes(ctx), nil
|
||||
case "length":
|
||||
return node.Length(), nil
|
||||
default:
|
||||
|
@ -23,10 +23,10 @@ func NewIterator(
|
||||
return &Iterator{node, 0}, nil
|
||||
}
|
||||
|
||||
func (iterator *Iterator) Next(_ context.Context) (value core.Value, key core.Value, err error) {
|
||||
func (iterator *Iterator) Next(ctx context.Context) (value core.Value, key core.Value, err error) {
|
||||
if iterator.node.Length() > iterator.pos {
|
||||
idx := iterator.pos
|
||||
val := iterator.node.GetChildNode(idx)
|
||||
val := iterator.node.GetChildNode(ctx, idx)
|
||||
|
||||
iterator.pos++
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
@ -8,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
LazyFactory func() (core.Value, error)
|
||||
LazyFactory func(ctx context.Context) (core.Value, error)
|
||||
|
||||
LazyValue struct {
|
||||
sync.Mutex
|
||||
@ -40,12 +41,12 @@ func (lv *LazyValue) Ready() bool {
|
||||
// Read returns an underlying value.
|
||||
// Not thread safe. Should not mutated.
|
||||
// @returns (Value) - Underlying value if successfully loaded, otherwise error
|
||||
func (lv *LazyValue) Read() (core.Value, error) {
|
||||
func (lv *LazyValue) Read(ctx context.Context) (core.Value, error) {
|
||||
lv.Lock()
|
||||
defer lv.Unlock()
|
||||
|
||||
if !lv.ready {
|
||||
lv.load()
|
||||
lv.load(ctx)
|
||||
}
|
||||
|
||||
return lv.value, lv.err
|
||||
@ -54,12 +55,12 @@ func (lv *LazyValue) Read() (core.Value, error) {
|
||||
// Write safely mutates an underlying value.
|
||||
// Loads a value if it's not ready.
|
||||
// Thread safe.
|
||||
func (lv *LazyValue) Write(writer func(v core.Value, err error)) {
|
||||
func (lv *LazyValue) Write(ctx context.Context, writer func(v core.Value, err error)) {
|
||||
lv.Lock()
|
||||
defer lv.Unlock()
|
||||
|
||||
if !lv.ready {
|
||||
lv.load()
|
||||
lv.load(ctx)
|
||||
}
|
||||
|
||||
writer(lv.value, lv.err)
|
||||
@ -76,8 +77,8 @@ func (lv *LazyValue) Reset() {
|
||||
lv.err = nil
|
||||
}
|
||||
|
||||
func (lv *LazyValue) load() {
|
||||
val, err := lv.factory()
|
||||
func (lv *LazyValue) load(ctx context.Context) {
|
||||
val, err := lv.factory(ctx)
|
||||
|
||||
if err == nil {
|
||||
lv.value = val
|
||||
|
@ -21,7 +21,7 @@ func SetInDocument(ctx context.Context, doc drivers.HTMLDocument, path []core.Va
|
||||
|
||||
switch segment {
|
||||
case "url", "URL":
|
||||
return doc.SetURL(values.NewString(value.String()))
|
||||
return doc.SetURL(ctx, values.NewString(value.String()))
|
||||
default:
|
||||
return SetInNode(ctx, doc, path, value)
|
||||
}
|
||||
@ -45,7 +45,7 @@ func SetInElement(ctx context.Context, el drivers.HTMLElement, path []core.Value
|
||||
if len(path) > 1 {
|
||||
attrName := path[1]
|
||||
|
||||
return el.SetAttribute(values.NewString(attrName.String()), values.NewString(value.String()))
|
||||
return el.SetAttribute(ctx, values.NewString(attrName.String()), values.NewString(value.String()))
|
||||
}
|
||||
|
||||
err := core.ValidateType(value, types.Object)
|
||||
@ -56,7 +56,7 @@ func SetInElement(ctx context.Context, el drivers.HTMLElement, path []core.Value
|
||||
|
||||
obj := value.(*values.Object)
|
||||
obj.ForEach(func(value core.Value, key string) bool {
|
||||
err = el.SetAttribute(values.NewString(key), values.NewString(value.String()))
|
||||
err = el.SetAttribute(ctx, values.NewString(key), values.NewString(value.String()))
|
||||
|
||||
return err == nil
|
||||
})
|
||||
@ -67,7 +67,7 @@ func SetInElement(ctx context.Context, el drivers.HTMLElement, path []core.Value
|
||||
return core.Error(ErrInvalidPath, PathToString(path[1:]))
|
||||
}
|
||||
|
||||
return el.SetValue(value)
|
||||
return el.SetValue(ctx, value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,14 @@ package drivers
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
)
|
||||
|
||||
const DefaultTimeout = time.Second * 30
|
||||
|
||||
type (
|
||||
ctxKey struct{}
|
||||
|
||||
|
9
pkg/drivers/helpers.go
Normal file
9
pkg/drivers/helpers.go
Normal file
@ -0,0 +1,9 @@
|
||||
package drivers
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
func WithDefaultTimeout(ctx context.Context) (context.Context, context.CancelFunc) {
|
||||
return context.WithTimeout(ctx, DefaultTimeout)
|
||||
}
|
@ -125,28 +125,28 @@ func (doc *HTMLDocument) NodeName() values.String {
|
||||
return "#document"
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) GetChildNodes() core.Value {
|
||||
return doc.element.GetChildNodes()
|
||||
func (doc *HTMLDocument) GetChildNodes(ctx context.Context) core.Value {
|
||||
return doc.element.GetChildNodes(ctx)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) GetChildNode(idx values.Int) core.Value {
|
||||
return doc.element.GetChildNode(idx)
|
||||
func (doc *HTMLDocument) GetChildNode(ctx context.Context, idx values.Int) core.Value {
|
||||
return doc.element.GetChildNode(ctx, idx)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) QuerySelector(selector values.String) core.Value {
|
||||
return doc.element.QuerySelector(selector)
|
||||
func (doc *HTMLDocument) QuerySelector(ctx context.Context, selector values.String) core.Value {
|
||||
return doc.element.QuerySelector(ctx, selector)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) QuerySelectorAll(selector values.String) core.Value {
|
||||
return doc.element.QuerySelectorAll(selector)
|
||||
func (doc *HTMLDocument) QuerySelectorAll(ctx context.Context, selector values.String) core.Value {
|
||||
return doc.element.QuerySelectorAll(ctx, selector)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) CountBySelector(selector values.String) values.Int {
|
||||
return doc.element.CountBySelector(selector)
|
||||
func (doc *HTMLDocument) CountBySelector(ctx context.Context, selector values.String) values.Int {
|
||||
return doc.element.CountBySelector(ctx, selector)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ExistsBySelector(selector values.String) values.Boolean {
|
||||
return doc.element.ExistsBySelector(selector)
|
||||
func (doc *HTMLDocument) ExistsBySelector(ctx context.Context, selector values.String) values.Boolean {
|
||||
return doc.element.ExistsBySelector(ctx, selector)
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) DocumentElement() drivers.HTMLElement {
|
||||
@ -157,75 +157,75 @@ func (doc *HTMLDocument) GetURL() core.Value {
|
||||
return doc.url
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) SetURL(_ values.String) error {
|
||||
func (doc *HTMLDocument) SetURL(_ context.Context, _ values.String) error {
|
||||
return core.ErrInvalidOperation
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) Navigate(_ values.String, _ values.Int) error {
|
||||
func (doc *HTMLDocument) Navigate(_ context.Context, _ values.String) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) NavigateBack(_ values.Int, _ values.Int) (values.Boolean, error) {
|
||||
func (doc *HTMLDocument) NavigateBack(_ context.Context, _ values.Int) (values.Boolean, error) {
|
||||
return false, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) NavigateForward(_ values.Int, _ values.Int) (values.Boolean, error) {
|
||||
func (doc *HTMLDocument) NavigateForward(_ context.Context, _ values.Int) (values.Boolean, error) {
|
||||
return false, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ClickBySelector(_ values.String) (values.Boolean, error) {
|
||||
func (doc *HTMLDocument) ClickBySelector(_ context.Context, _ values.String) (values.Boolean, error) {
|
||||
return false, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ClickBySelectorAll(_ values.String) (values.Boolean, error) {
|
||||
func (doc *HTMLDocument) ClickBySelectorAll(_ context.Context, _ values.String) (values.Boolean, error) {
|
||||
return false, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) InputBySelector(_ values.String, _ core.Value, _ values.Int) (values.Boolean, error) {
|
||||
func (doc *HTMLDocument) InputBySelector(_ context.Context, _ values.String, _ core.Value, _ values.Int) (values.Boolean, error) {
|
||||
return false, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) SelectBySelector(_ values.String, _ *values.Array) (*values.Array, error) {
|
||||
func (doc *HTMLDocument) SelectBySelector(_ context.Context, _ values.String, _ *values.Array) (*values.Array, error) {
|
||||
return nil, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) HoverBySelector(_ values.String) error {
|
||||
func (doc *HTMLDocument) HoverBySelector(_ context.Context, _ values.String) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) PrintToPDF(_ drivers.PDFParams) (values.Binary, error) {
|
||||
func (doc *HTMLDocument) PrintToPDF(_ context.Context, _ drivers.PDFParams) (values.Binary, error) {
|
||||
return nil, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) CaptureScreenshot(_ drivers.ScreenshotParams) (values.Binary, error) {
|
||||
func (doc *HTMLDocument) CaptureScreenshot(_ context.Context, _ drivers.ScreenshotParams) (values.Binary, error) {
|
||||
return nil, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ScrollTop() error {
|
||||
func (doc *HTMLDocument) ScrollTop(_ context.Context) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ScrollBottom() error {
|
||||
func (doc *HTMLDocument) ScrollBottom(_ context.Context) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) ScrollBySelector(_ values.String) error {
|
||||
func (doc *HTMLDocument) ScrollBySelector(_ context.Context, _ values.String) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForNavigation(_ values.Int) error {
|
||||
func (doc *HTMLDocument) WaitForNavigation(_ context.Context) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForSelector(_ values.String, _ values.Int) error {
|
||||
func (doc *HTMLDocument) WaitForSelector(_ context.Context, _ values.String) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForClassBySelector(_, _ values.String, _ values.Int) error {
|
||||
func (doc *HTMLDocument) WaitForClassBySelector(_ context.Context, _, _ values.String) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) WaitForClassBySelectorAll(_, _ values.String, _ values.Int) error {
|
||||
func (doc *HTMLDocument) WaitForClassBySelectorAll(_ context.Context, _, _ values.String) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ func NewHTMLElement(node *goquery.Selection) (drivers.HTMLElement, error) {
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(nd.InnerText().String())
|
||||
return json.Marshal(nd.InnerText(context.Background()).String())
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) Type() core.Type {
|
||||
@ -35,7 +35,7 @@ func (nd *HTMLElement) Type() core.Type {
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) String() string {
|
||||
return nd.InnerHTML().String()
|
||||
return nd.InnerHTML(context.Background()).String()
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) Compare(other core.Value) int64 {
|
||||
@ -43,7 +43,10 @@ func (nd *HTMLElement) Compare(other core.Value) int64 {
|
||||
case drivers.HTMLElementType:
|
||||
other := other.(drivers.HTMLElement)
|
||||
|
||||
return nd.InnerHTML().Compare(other.InnerHTML())
|
||||
ctx, fn := drivers.WithDefaultTimeout(context.Background())
|
||||
defer fn()
|
||||
|
||||
return nd.InnerHTML(ctx).Compare(other.InnerHTML(ctx))
|
||||
default:
|
||||
return drivers.Compare(nd.Type(), other.Type())
|
||||
}
|
||||
@ -101,7 +104,7 @@ func (nd *HTMLElement) Length() values.Int {
|
||||
return nd.children.Length()
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) GetValue() core.Value {
|
||||
func (nd *HTMLElement) GetValue(_ context.Context) core.Value {
|
||||
val, ok := nd.selection.Attr("value")
|
||||
|
||||
if ok {
|
||||
@ -111,17 +114,17 @@ func (nd *HTMLElement) GetValue() core.Value {
|
||||
return values.EmptyString
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) SetValue(value core.Value) error {
|
||||
func (nd *HTMLElement) SetValue(_ context.Context, value core.Value) error {
|
||||
nd.selection.SetAttr("value", value.String())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) InnerText() values.String {
|
||||
func (nd *HTMLElement) InnerText(_ context.Context) values.String {
|
||||
return values.NewString(nd.selection.Text())
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) InnerHTML() values.String {
|
||||
func (nd *HTMLElement) InnerHTML(_ context.Context) values.String {
|
||||
h, err := nd.selection.Html()
|
||||
|
||||
if err != nil {
|
||||
@ -131,7 +134,7 @@ func (nd *HTMLElement) InnerHTML() values.String {
|
||||
return values.NewString(h)
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) GetAttributes() core.Value {
|
||||
func (nd *HTMLElement) GetAttributes(_ context.Context) core.Value {
|
||||
if nd.attrs == nil {
|
||||
nd.attrs = nd.parseAttrs()
|
||||
}
|
||||
@ -139,7 +142,7 @@ func (nd *HTMLElement) GetAttributes() core.Value {
|
||||
return nd.attrs
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) GetAttribute(name values.String) core.Value {
|
||||
func (nd *HTMLElement) GetAttribute(_ context.Context, name values.String) core.Value {
|
||||
v, ok := nd.selection.Attr(name.String())
|
||||
|
||||
if ok {
|
||||
@ -149,13 +152,13 @@ func (nd *HTMLElement) GetAttribute(name values.String) core.Value {
|
||||
return values.None
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) SetAttribute(name, value values.String) error {
|
||||
func (nd *HTMLElement) SetAttribute(_ context.Context, name, value values.String) error {
|
||||
nd.selection.SetAttr(string(name), string(value))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) GetChildNodes() core.Value {
|
||||
func (nd *HTMLElement) GetChildNodes(_ context.Context) core.Value {
|
||||
if nd.children == nil {
|
||||
nd.children = nd.parseChildren()
|
||||
}
|
||||
@ -163,7 +166,7 @@ func (nd *HTMLElement) GetChildNodes() core.Value {
|
||||
return nd.children
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) GetChildNode(idx values.Int) core.Value {
|
||||
func (nd *HTMLElement) GetChildNode(_ context.Context, idx values.Int) core.Value {
|
||||
if nd.children == nil {
|
||||
nd.children = nd.parseChildren()
|
||||
}
|
||||
@ -171,7 +174,7 @@ func (nd *HTMLElement) GetChildNode(idx values.Int) core.Value {
|
||||
return nd.children.Get(idx)
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) QuerySelector(selector values.String) core.Value {
|
||||
func (nd *HTMLElement) QuerySelector(_ context.Context, selector values.String) core.Value {
|
||||
selection := nd.selection.Find(selector.String())
|
||||
|
||||
if selection == nil {
|
||||
@ -187,7 +190,7 @@ func (nd *HTMLElement) QuerySelector(selector values.String) core.Value {
|
||||
return res
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) QuerySelectorAll(selector values.String) core.Value {
|
||||
func (nd *HTMLElement) QuerySelectorAll(_ context.Context, selector values.String) core.Value {
|
||||
selection := nd.selection.Find(selector.String())
|
||||
|
||||
if selection == nil {
|
||||
@ -207,7 +210,7 @@ func (nd *HTMLElement) QuerySelectorAll(selector values.String) core.Value {
|
||||
return arr
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) InnerHTMLBySelector(selector values.String) values.String {
|
||||
func (nd *HTMLElement) InnerHTMLBySelector(_ context.Context, selector values.String) values.String {
|
||||
selection := nd.selection.Find(selector.String())
|
||||
|
||||
str, err := selection.Html()
|
||||
@ -220,7 +223,7 @@ func (nd *HTMLElement) InnerHTMLBySelector(selector values.String) values.String
|
||||
return values.NewString(str)
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) InnerHTMLBySelectorAll(selector values.String) *values.Array {
|
||||
func (nd *HTMLElement) InnerHTMLBySelectorAll(_ context.Context, selector values.String) *values.Array {
|
||||
selection := nd.selection.Find(selector.String())
|
||||
arr := values.NewArray(selection.Length())
|
||||
|
||||
@ -236,13 +239,13 @@ func (nd *HTMLElement) InnerHTMLBySelectorAll(selector values.String) *values.Ar
|
||||
return arr
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) InnerTextBySelector(selector values.String) values.String {
|
||||
func (nd *HTMLElement) InnerTextBySelector(_ context.Context, selector values.String) values.String {
|
||||
selection := nd.selection.Find(selector.String())
|
||||
|
||||
return values.NewString(selection.Text())
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) InnerTextBySelectorAll(selector values.String) *values.Array {
|
||||
func (nd *HTMLElement) InnerTextBySelectorAll(_ context.Context, selector values.String) *values.Array {
|
||||
selection := nd.selection.Find(selector.String())
|
||||
arr := values.NewArray(selection.Length())
|
||||
|
||||
@ -253,7 +256,7 @@ func (nd *HTMLElement) InnerTextBySelectorAll(selector values.String) *values.Ar
|
||||
return arr
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) CountBySelector(selector values.String) values.Int {
|
||||
func (nd *HTMLElement) CountBySelector(_ context.Context, selector values.String) values.Int {
|
||||
selection := nd.selection.Find(selector.String())
|
||||
|
||||
if selection == nil {
|
||||
@ -263,7 +266,7 @@ func (nd *HTMLElement) CountBySelector(selector values.String) values.Int {
|
||||
return values.NewInt(selection.Size())
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) ExistsBySelector(selector values.String) values.Boolean {
|
||||
func (nd *HTMLElement) ExistsBySelector(_ context.Context, selector values.String) values.Boolean {
|
||||
selection := nd.selection.Closest(selector.String())
|
||||
|
||||
if selection == nil {
|
||||
@ -285,27 +288,27 @@ func (nd *HTMLElement) Iterate(_ context.Context) (core.Iterator, error) {
|
||||
return common.NewIterator(nd)
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) Click() (values.Boolean, error) {
|
||||
func (nd *HTMLElement) Click(_ context.Context) (values.Boolean, error) {
|
||||
return false, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) Input(_ core.Value, _ values.Int) error {
|
||||
func (nd *HTMLElement) Input(_ context.Context, _ core.Value, _ values.Int) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) Select(_ *values.Array) (*values.Array, error) {
|
||||
func (nd *HTMLElement) Select(_ context.Context, _ *values.Array) (*values.Array, error) {
|
||||
return nil, core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) ScrollIntoView() error {
|
||||
func (nd *HTMLElement) ScrollIntoView(_ context.Context) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) Hover() error {
|
||||
func (nd *HTMLElement) Hover(_ context.Context) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
func (nd *HTMLElement) WaitForClass(_ values.String, _ values.Int) error {
|
||||
func (nd *HTMLElement) WaitForClass(_ context.Context, _ values.String) error {
|
||||
return core.ErrNotSupported
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package http_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/drivers"
|
||||
"github.com/MontFerret/ferret/pkg/drivers/http"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
@ -321,7 +322,7 @@ func TestElement(t *testing.T) {
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
v := el.GetValue()
|
||||
v := el.GetValue(context.Background())
|
||||
|
||||
So(v, ShouldEqual, "find")
|
||||
})
|
||||
@ -348,7 +349,7 @@ func TestElement(t *testing.T) {
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
v := el.InnerText()
|
||||
v := el.InnerText(context.Background())
|
||||
|
||||
So(v, ShouldEqual, "Ferret")
|
||||
})
|
||||
@ -375,7 +376,7 @@ func TestElement(t *testing.T) {
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
v := el.InnerHTML()
|
||||
v := el.InnerHTML(context.Background())
|
||||
|
||||
So(v, ShouldEqual, "<h2>Ferret</h2>")
|
||||
})
|
||||
@ -391,7 +392,7 @@ func TestElement(t *testing.T) {
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
found := el.QuerySelector(values.NewString("body .card-img-top:nth-child(1)"))
|
||||
found := el.QuerySelector(context.Background(), values.NewString("body .card-img-top:nth-child(1)"))
|
||||
|
||||
So(found, ShouldNotEqual, values.None)
|
||||
|
||||
@ -413,7 +414,7 @@ func TestElement(t *testing.T) {
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
v := el.CountBySelector(values.NewString("head meta"))
|
||||
v := el.CountBySelector(context.Background(), values.NewString("head meta"))
|
||||
|
||||
So(v, ShouldEqual, 4)
|
||||
})
|
||||
|
@ -1,6 +1,7 @@
|
||||
package drivers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/collections"
|
||||
@ -24,56 +25,56 @@ type (
|
||||
|
||||
NodeName() values.String
|
||||
|
||||
GetChildNodes() core.Value
|
||||
GetChildNodes(ctx context.Context) core.Value
|
||||
|
||||
GetChildNode(idx values.Int) core.Value
|
||||
GetChildNode(ctx context.Context, idx values.Int) core.Value
|
||||
|
||||
QuerySelector(selector values.String) core.Value
|
||||
QuerySelector(ctx context.Context, selector values.String) core.Value
|
||||
|
||||
QuerySelectorAll(selector values.String) core.Value
|
||||
QuerySelectorAll(ctx context.Context, selector values.String) core.Value
|
||||
|
||||
CountBySelector(selector values.String) values.Int
|
||||
CountBySelector(ctx context.Context, selector values.String) values.Int
|
||||
|
||||
ExistsBySelector(selector values.String) values.Boolean
|
||||
ExistsBySelector(ctx context.Context, selector values.String) values.Boolean
|
||||
}
|
||||
|
||||
// HTMLElement is the most general base interface which most objects in a Document implement.
|
||||
HTMLElement interface {
|
||||
HTMLNode
|
||||
|
||||
InnerText() values.String
|
||||
InnerText(ctx context.Context) values.String
|
||||
|
||||
InnerHTML() values.String
|
||||
InnerHTML(ctx context.Context) values.String
|
||||
|
||||
GetValue() core.Value
|
||||
GetValue(ctx context.Context) core.Value
|
||||
|
||||
SetValue(value core.Value) error
|
||||
SetValue(ctx context.Context, value core.Value) error
|
||||
|
||||
GetAttributes() core.Value
|
||||
GetAttributes(ctx context.Context) core.Value
|
||||
|
||||
GetAttribute(name values.String) core.Value
|
||||
GetAttribute(ctx context.Context, name values.String) core.Value
|
||||
|
||||
SetAttribute(name, value values.String) error
|
||||
SetAttribute(ctx context.Context, name, value values.String) error
|
||||
|
||||
InnerHTMLBySelector(selector values.String) values.String
|
||||
InnerHTMLBySelector(ctx context.Context, selector values.String) values.String
|
||||
|
||||
InnerHTMLBySelectorAll(selector values.String) *values.Array
|
||||
InnerHTMLBySelectorAll(ctx context.Context, selector values.String) *values.Array
|
||||
|
||||
InnerTextBySelector(selector values.String) values.String
|
||||
InnerTextBySelector(ctx context.Context, selector values.String) values.String
|
||||
|
||||
InnerTextBySelectorAll(selector values.String) *values.Array
|
||||
InnerTextBySelectorAll(ctx context.Context, selector values.String) *values.Array
|
||||
|
||||
Click() (values.Boolean, error)
|
||||
Click(ctx context.Context) (values.Boolean, error)
|
||||
|
||||
Input(value core.Value, delay values.Int) error
|
||||
Input(ctx context.Context, value core.Value, delay values.Int) error
|
||||
|
||||
Select(value *values.Array) (*values.Array, error)
|
||||
Select(ctx context.Context, value *values.Array) (*values.Array, error)
|
||||
|
||||
ScrollIntoView() error
|
||||
ScrollIntoView(ctx context.Context) error
|
||||
|
||||
Hover() error
|
||||
Hover(ctx context.Context) error
|
||||
|
||||
WaitForClass(class values.String, timeout values.Int) error
|
||||
WaitForClass(ctx context.Context, class values.String) error
|
||||
}
|
||||
|
||||
// The Document interface represents any web page loaded in the browser
|
||||
@ -85,40 +86,40 @@ type (
|
||||
|
||||
GetURL() core.Value
|
||||
|
||||
SetURL(url values.String) error
|
||||
SetURL(ctx context.Context, url values.String) error
|
||||
|
||||
Navigate(url values.String, timeout values.Int) error
|
||||
Navigate(ctx context.Context, url values.String) error
|
||||
|
||||
NavigateBack(skip values.Int, timeout values.Int) (values.Boolean, error)
|
||||
NavigateBack(ctx context.Context, skip values.Int) (values.Boolean, error)
|
||||
|
||||
NavigateForward(skip values.Int, timeout values.Int) (values.Boolean, error)
|
||||
NavigateForward(ctx context.Context, skip values.Int) (values.Boolean, error)
|
||||
|
||||
ClickBySelector(selector values.String) (values.Boolean, error)
|
||||
ClickBySelector(ctx context.Context, selector values.String) (values.Boolean, error)
|
||||
|
||||
ClickBySelectorAll(selector values.String) (values.Boolean, error)
|
||||
ClickBySelectorAll(ctx context.Context, selector values.String) (values.Boolean, error)
|
||||
|
||||
InputBySelector(selector values.String, value core.Value, delay values.Int) (values.Boolean, error)
|
||||
InputBySelector(ctx context.Context, selector values.String, value core.Value, delay values.Int) (values.Boolean, error)
|
||||
|
||||
SelectBySelector(selector values.String, value *values.Array) (*values.Array, error)
|
||||
SelectBySelector(ctx context.Context, selector values.String, value *values.Array) (*values.Array, error)
|
||||
|
||||
HoverBySelector(selector values.String) error
|
||||
HoverBySelector(ctx context.Context, selector values.String) error
|
||||
|
||||
PrintToPDF(params PDFParams) (values.Binary, error)
|
||||
PrintToPDF(ctx context.Context, params PDFParams) (values.Binary, error)
|
||||
|
||||
CaptureScreenshot(params ScreenshotParams) (values.Binary, error)
|
||||
CaptureScreenshot(ctx context.Context, params ScreenshotParams) (values.Binary, error)
|
||||
|
||||
ScrollTop() error
|
||||
ScrollTop(ctx context.Context) error
|
||||
|
||||
ScrollBottom() error
|
||||
ScrollBottom(ctx context.Context) error
|
||||
|
||||
ScrollBySelector(selector values.String) error
|
||||
ScrollBySelector(ctx context.Context, selector values.String) error
|
||||
|
||||
WaitForNavigation(timeout values.Int) error
|
||||
WaitForNavigation(ctx context.Context) error
|
||||
|
||||
WaitForSelector(selector values.String, timeout values.Int) error
|
||||
WaitForSelector(ctx context.Context, selector values.String) error
|
||||
|
||||
WaitForClassBySelector(selector, class values.String, timeout values.Int) error
|
||||
WaitForClassBySelector(ctx context.Context, selector, class values.String) error
|
||||
|
||||
WaitForClassBySelectorAll(selector, class values.String, timeout values.Int) error
|
||||
WaitForClassBySelectorAll(ctx context.Context, selector, class values.String) error
|
||||
}
|
||||
)
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
// Click dispatches click event on a given element
|
||||
// @param source (Document | Element) - Event source.
|
||||
// @param selector (String, optional) - Optional selector. Only used when a document instance is passed.
|
||||
func Click(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func Click(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 2)
|
||||
|
||||
if err != nil {
|
||||
@ -25,7 +25,7 @@ func Click(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
return values.False, err
|
||||
}
|
||||
|
||||
return el.Click()
|
||||
return el.Click(ctx)
|
||||
}
|
||||
|
||||
// CLICK(doc, selector)
|
||||
@ -37,5 +37,5 @@ func Click(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
|
||||
selector := args[1].String()
|
||||
|
||||
return doc.ClickBySelector(values.NewString(selector))
|
||||
return doc.ClickBySelector(ctx, values.NewString(selector))
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
// @param source (Document) - Document.
|
||||
// @param selector (String) - Selector.
|
||||
// @returns (Boolean) - Returns true if matched at least one element.
|
||||
func ClickAll(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func ClickAll(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 2, 2)
|
||||
|
||||
if err != nil {
|
||||
@ -34,5 +34,5 @@ func ClickAll(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
return doc.ClickBySelectorAll(values.NewString(selector))
|
||||
return doc.ClickBySelectorAll(ctx, values.NewString(selector))
|
||||
}
|
||||
|
@ -14,14 +14,14 @@ import (
|
||||
// @param docOrEl (HTMLDocument|HTMLElement) - Parent document or element.
|
||||
// @param selector (String) - CSS selector.
|
||||
// @returns (HTMLElement | None) - Returns an HTMLElement if found, otherwise NONE.
|
||||
func Element(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func Element(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
el, selector, err := queryArgs(args)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
return el.QuerySelector(selector), nil
|
||||
return el.QuerySelector(ctx, selector), nil
|
||||
}
|
||||
|
||||
func queryArgs(args []core.Value) (drivers.HTMLNode, values.String, error) {
|
||||
|
@ -11,12 +11,12 @@ import (
|
||||
// @param docOrEl (HTMLDocument|HTMLNode) - Parent document or element.
|
||||
// @param selector (String) - CSS selector.
|
||||
// @returns (Boolean) - A boolean value indicating whether there is an element matched by selector.
|
||||
func ElementExists(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func ElementExists(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
el, selector, err := queryArgs(args)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
return el.ExistsBySelector(selector), nil
|
||||
return el.ExistsBySelector(ctx, selector), nil
|
||||
}
|
||||
|
@ -12,12 +12,12 @@ import (
|
||||
// @param docOrEl (HTMLDocument|HTMLNode) - Parent document or element.
|
||||
// @param selector (String) - CSS selector.
|
||||
// @returns (Array) - Returns an array of found HTML element.
|
||||
func Elements(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func Elements(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
el, selector, err := queryArgs(args)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
return el.QuerySelectorAll(selector), nil
|
||||
return el.QuerySelectorAll(ctx, selector), nil
|
||||
}
|
||||
|
@ -12,12 +12,12 @@ import (
|
||||
// @param docOrEl (HTMLDocument|HTMLNode) - Parent document or element.
|
||||
// @param selector (String) - CSS selector.
|
||||
// @returns (Int) - A number of found HTML elements by a given CSS selector.
|
||||
func ElementsCount(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func ElementsCount(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
el, selector, err := queryArgs(args)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
return el.CountBySelector(selector), nil
|
||||
return el.CountBySelector(ctx, selector), nil
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
// If there's no element matching selector, the method returns an error.
|
||||
// @param docOrEl (HTMLDocument|HTMLElement) - Target document or element.
|
||||
// @param selector (String, options) - If document is passed, this param must represent an element selector.
|
||||
func Hover(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func Hover(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 2)
|
||||
|
||||
if err != nil {
|
||||
@ -38,11 +38,11 @@ func Hover(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
doc := args[0].(drivers.HTMLDocument)
|
||||
selector := args[1].(values.String)
|
||||
|
||||
return values.None, doc.HoverBySelector(selector)
|
||||
return values.None, doc.HoverBySelector(ctx, selector)
|
||||
}
|
||||
|
||||
// Element
|
||||
el := args[0].(drivers.HTMLElement)
|
||||
|
||||
return values.None, el.Hover()
|
||||
return values.None, el.Hover(ctx)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
// @param doc (Document|Element) - Parent document or element.
|
||||
// @param selector (String, optional) - String of CSS selector.
|
||||
// @returns (String) - Inner HTML string if an element found, otherwise empty string.
|
||||
func InnerHTML(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func InnerHTML(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 2)
|
||||
|
||||
if err != nil {
|
||||
@ -33,7 +33,7 @@ func InnerHTML(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
}
|
||||
|
||||
if len(args) == 1 {
|
||||
return el.InnerHTML(), nil
|
||||
return el.InnerHTML(ctx), nil
|
||||
}
|
||||
|
||||
err = core.ValidateType(args[1], types.String)
|
||||
@ -44,5 +44,5 @@ func InnerHTML(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
|
||||
selector := args[1].(values.String)
|
||||
|
||||
return el.InnerHTMLBySelector(selector), nil
|
||||
return el.InnerHTMLBySelector(ctx, selector), nil
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
// @param doc (HTMLDocument|HTMLElement) - Parent document or element.
|
||||
// @param selector (String) - String of CSS selector.
|
||||
// @returns (String) - An array of inner HTML strings if any element found, otherwise empty array.
|
||||
func InnerHTMLAll(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func InnerHTMLAll(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 2, 2)
|
||||
|
||||
if err != nil {
|
||||
@ -40,5 +40,5 @@ func InnerHTMLAll(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
|
||||
selector := args[1].(values.String)
|
||||
|
||||
return el.InnerHTMLBySelectorAll(selector), nil
|
||||
return el.InnerHTMLBySelectorAll(ctx, selector), nil
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
// @param doc (HTMLDocument|HTMLElement) - Parent document or element.
|
||||
// @param selector (String, optional) - String of CSS selector.
|
||||
// @returns (String) - Inner text if an element found, otherwise empty string.
|
||||
func InnerText(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func InnerText(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 2)
|
||||
|
||||
if err != nil {
|
||||
@ -26,7 +26,7 @@ func InnerText(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
}
|
||||
|
||||
if len(args) == 1 {
|
||||
return el.InnerText(), nil
|
||||
return el.InnerText(ctx), nil
|
||||
}
|
||||
|
||||
err = core.ValidateType(args[1], types.String)
|
||||
@ -37,5 +37,5 @@ func InnerText(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
|
||||
selector := args[1].(values.String)
|
||||
|
||||
return el.InnerTextBySelector(selector), nil
|
||||
return el.InnerTextBySelector(ctx, selector), nil
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
// @param doc (HTMLDocument|HTMLElement) - Parent document or element.
|
||||
// @param selector (String) - String of CSS selector.
|
||||
// @returns (String) - An array of inner text if any element found, otherwise empty array.
|
||||
func InnerTextAll(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func InnerTextAll(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 2, 2)
|
||||
|
||||
if err != nil {
|
||||
@ -40,5 +40,5 @@ func InnerTextAll(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
|
||||
selector := args[1].(values.String)
|
||||
|
||||
return el.InnerTextBySelectorAll(selector), nil
|
||||
return el.InnerTextBySelectorAll(ctx, selector), nil
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
// @param value (String) - Target value.
|
||||
// @param delay (Int, optional) - Waits delay milliseconds between keystrokes
|
||||
// @returns (Boolean) - Returns true if an element was found.
|
||||
func Input(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func Input(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 2, 4)
|
||||
|
||||
if err != nil {
|
||||
@ -54,7 +54,7 @@ func Input(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
delay = arg4.(values.Int)
|
||||
}
|
||||
|
||||
return doc.InputBySelector(arg2.(values.String), args[2], delay)
|
||||
return doc.InputBySelector(ctx, arg2.(values.String), args[2], delay)
|
||||
}
|
||||
|
||||
el := arg1.(drivers.HTMLElement)
|
||||
@ -72,7 +72,7 @@ func Input(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
delay = arg3.(values.Int)
|
||||
}
|
||||
|
||||
err = el.Input(args[1], delay)
|
||||
err = el.Input(ctx, args[1], delay)
|
||||
|
||||
if err != nil {
|
||||
return values.False, err
|
||||
|
@ -2,11 +2,11 @@ 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"
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultTimeout = 5000
|
||||
@ -67,6 +67,13 @@ func ValidateDocument(ctx context.Context, value core.Value) (core.Value, error)
|
||||
return doc, nil
|
||||
}
|
||||
|
||||
func waitTimeout(ctx context.Context, value values.Int) (context.Context, context.CancelFunc) {
|
||||
return context.WithTimeout(
|
||||
ctx,
|
||||
time.Duration(value)*time.Millisecond,
|
||||
)
|
||||
}
|
||||
|
||||
func resolveElement(value core.Value) (drivers.HTMLElement, error) {
|
||||
vt := value.Type()
|
||||
|
||||
|
@ -2,7 +2,6 @@ package html
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
@ -14,7 +13,7 @@ import (
|
||||
// @param doc (Document) - Target document.
|
||||
// @param url (String) - Target url to navigate.
|
||||
// @param timeout (Int, optional) - Optional timeout. Default is 5000.
|
||||
func Navigate(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func Navigate(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 2, 3)
|
||||
|
||||
if err != nil {
|
||||
@ -39,5 +38,8 @@ func Navigate(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout = args[2].(values.Int)
|
||||
}
|
||||
|
||||
return values.None, doc.Navigate(args[1].(values.String), timeout)
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return values.None, doc.Navigate(ctx, args[1].(values.String))
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package html
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
@ -15,7 +14,7 @@ import (
|
||||
// @param entry (Int, optional) - Optional value indicating how many pages to skip. Default 1.
|
||||
// @param timeout (Int, optional) - Optional timeout. Default is 5000.
|
||||
// @returns (Boolean) - Returns TRUE if history exists and the operation succeeded, otherwise FALSE.
|
||||
func NavigateBack(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func NavigateBack(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 3)
|
||||
|
||||
if err != nil {
|
||||
@ -51,5 +50,8 @@ func NavigateBack(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout = args[2].(values.Int)
|
||||
}
|
||||
|
||||
return doc.NavigateBack(skip, timeout)
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return doc.NavigateBack(ctx, skip)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package html
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
@ -15,7 +14,7 @@ import (
|
||||
// @param entry (Int, optional) - Optional value indicating how many pages to skip. Default 1.
|
||||
// @param timeout (Int, optional) - Optional timeout. Default is 5000.
|
||||
// @returns (Boolean) - Returns TRUE if history exists and the operation succeeded, otherwise FALSE.
|
||||
func NavigateForward(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func NavigateForward(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 3)
|
||||
|
||||
if err != nil {
|
||||
@ -51,5 +50,8 @@ func NavigateForward(_ context.Context, args ...core.Value) (core.Value, error)
|
||||
timeout = args[2].(values.Int)
|
||||
}
|
||||
|
||||
return doc.NavigateForward(skip, timeout)
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return doc.NavigateForward(ctx, skip)
|
||||
}
|
||||
|
@ -85,14 +85,14 @@ func (p *Paging) Iterate(_ context.Context) (core.Iterator, error) {
|
||||
return &PagingIterator{p.document, p.selector, -1}, nil
|
||||
}
|
||||
|
||||
func (i *PagingIterator) Next(_ context.Context) (core.Value, core.Value, error) {
|
||||
func (i *PagingIterator) Next(ctx context.Context) (core.Value, core.Value, error) {
|
||||
i.pos++
|
||||
|
||||
if i.pos == 0 {
|
||||
return values.ZeroInt, values.ZeroInt, nil
|
||||
}
|
||||
|
||||
clicked, err := i.document.ClickBySelector(i.selector)
|
||||
clicked, err := i.document.ClickBySelector(ctx, i.selector)
|
||||
|
||||
if err != nil {
|
||||
return values.None, values.None, err
|
||||
|
@ -292,7 +292,7 @@ func PDF(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
}
|
||||
}
|
||||
|
||||
pdf, err := doc.PrintToPDF(pdfParams)
|
||||
pdf, err := doc.PrintToPDF(ctx, pdfParams)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
|
@ -155,7 +155,7 @@ func Screenshot(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
}
|
||||
}
|
||||
|
||||
scr, err := doc.CaptureScreenshot(screenshotParams)
|
||||
scr, err := doc.CaptureScreenshot(ctx, screenshotParams)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
// ScrollTop scrolls the document's window to its bottom.
|
||||
// @param doc (HTMLDocument) - Target document.
|
||||
func ScrollBottom(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func ScrollBottom(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 1)
|
||||
|
||||
if err != nil {
|
||||
@ -29,5 +29,5 @@ func ScrollBottom(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
return values.None, doc.ScrollBottom()
|
||||
return values.None, doc.ScrollBottom(ctx)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
// ScrollInto scrolls an element on.
|
||||
// @param docOrEl (HTMLDocument|HTMLElement) - Target document or element.
|
||||
// @param selector (String, options) - If document is passed, this param must represent an element selector.
|
||||
func ScrollInto(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func ScrollInto(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 2)
|
||||
|
||||
if err != nil {
|
||||
@ -36,7 +36,7 @@ func ScrollInto(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
doc := args[0].(drivers.HTMLDocument)
|
||||
selector := args[1].(values.String)
|
||||
|
||||
return values.None, doc.ScrollBySelector(selector)
|
||||
return values.None, doc.ScrollBySelector(ctx, selector)
|
||||
}
|
||||
|
||||
err = core.ValidateType(args[0], drivers.HTMLElementType)
|
||||
@ -48,5 +48,5 @@ func ScrollInto(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
// Element
|
||||
el := args[0].(drivers.HTMLElement)
|
||||
|
||||
return values.None, el.ScrollIntoView()
|
||||
return values.None, el.ScrollIntoView(ctx)
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
// ScrollTop scrolls the document's window to its top.
|
||||
// @param doc (HTMLDocument) - Target document.
|
||||
func ScrollTop(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func ScrollTop(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 1)
|
||||
|
||||
if err != nil {
|
||||
@ -29,5 +29,5 @@ func ScrollTop(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
return values.None, doc.ScrollTop()
|
||||
return values.None, doc.ScrollTop(ctx)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
// @param valueOrSelector (String | Array<String>) - Selector or a an array of strings as a value.
|
||||
// @param value (Array<String) - Target value. Optional.
|
||||
// @returns (Array<String>) - Returns an array of selected values.
|
||||
func Select(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func Select(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 2, 4)
|
||||
|
||||
if err != nil {
|
||||
@ -46,7 +46,7 @@ func Select(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
return values.False, err
|
||||
}
|
||||
|
||||
return doc.SelectBySelector(arg2.(values.String), arg3.(*values.Array))
|
||||
return doc.SelectBySelector(ctx, arg2.(values.String), arg3.(*values.Array))
|
||||
}
|
||||
|
||||
el := arg1.(drivers.HTMLElement)
|
||||
@ -58,5 +58,5 @@ func Select(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
return values.False, err
|
||||
}
|
||||
|
||||
return el.Select(arg2.(*values.Array))
|
||||
return el.Select(ctx, arg2.(*values.Array))
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package html
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/drivers"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
@ -18,7 +17,7 @@ import (
|
||||
// Otherwise timeout.
|
||||
// @param timeout (Int, optional) - If document is passed, this param must represent timeout.
|
||||
// Otherwise not passed.
|
||||
func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func WaitClass(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 2, 4)
|
||||
|
||||
if err != nil {
|
||||
@ -72,7 +71,10 @@ func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout = args[3].(values.Int)
|
||||
}
|
||||
|
||||
return values.None, doc.WaitForClassBySelector(selector, class, timeout)
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return values.None, doc.WaitForClassBySelector(ctx, selector, class)
|
||||
}
|
||||
|
||||
el := arg1.(drivers.HTMLElement)
|
||||
@ -88,5 +90,8 @@ func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout = args[2].(values.Int)
|
||||
}
|
||||
|
||||
return values.None, el.WaitForClass(class, timeout)
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return values.None, el.WaitForClass(ctx, class)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package html
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
@ -14,7 +13,7 @@ import (
|
||||
// @param selector (String) - String of CSS selector.
|
||||
// @param class (String) - String of target CSS class.
|
||||
// @param timeout (Int, optional) - Optional timeout.
|
||||
func WaitClassAll(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func WaitClassAll(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 3, 4)
|
||||
|
||||
if err != nil {
|
||||
@ -55,5 +54,8 @@ func WaitClassAll(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout = args[3].(values.Int)
|
||||
}
|
||||
|
||||
return values.None, doc.WaitForClassBySelectorAll(selector, class, timeout)
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return values.None, doc.WaitForClassBySelectorAll(ctx, selector, class)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package html
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
@ -13,7 +12,7 @@ import (
|
||||
// @param doc (HTMLDocument) - Driver HTMLDocument.
|
||||
// @param selector (String) - Target element's selector.
|
||||
// @param timeout (Int, optional) - Optional timeout. Default 5000 ms.
|
||||
func WaitElement(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func WaitElement(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 2, 3)
|
||||
|
||||
if err != nil {
|
||||
@ -39,5 +38,8 @@ func WaitElement(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout = args[2].(values.Int)
|
||||
}
|
||||
|
||||
return values.None, doc.WaitForSelector(values.NewString(selector), timeout)
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return values.None, doc.WaitForSelector(ctx, values.NewString(selector))
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package html
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
@ -12,7 +11,7 @@ import (
|
||||
// Stops the execution until the navigation ends or operation times out.
|
||||
// @param doc (HTMLDocument) - Driver HTMLDocument.
|
||||
// @param timeout (Int, optional) - Optional timeout. Default 5000 ms.
|
||||
func WaitNavigation(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
func WaitNavigation(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
err := core.ValidateArgs(args, 1, 2)
|
||||
|
||||
if err != nil {
|
||||
@ -37,5 +36,8 @@ func WaitNavigation(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
timeout = args[1].(values.Int)
|
||||
}
|
||||
|
||||
return values.None, doc.WaitForNavigation(timeout)
|
||||
ctx, fn := waitTimeout(ctx, timeout)
|
||||
defer fn()
|
||||
|
||||
return values.None, doc.WaitForNavigation(ctx)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user