use consistent context.Context var names

This commit is contained in:
Daniel Martí 2019-03-20 12:08:50 +00:00
parent 61f0a8da68
commit c109f6ebfd
7 changed files with 116 additions and 116 deletions

View File

@ -18,8 +18,8 @@ type Action interface {
type ActionFunc func(context.Context, cdp.Executor) error type ActionFunc func(context.Context, cdp.Executor) error
// Do executes the func f using the provided context and frame handler. // Do executes the func f using the provided context and frame handler.
func (f ActionFunc) Do(ctxt context.Context, h cdp.Executor) error { func (f ActionFunc) Do(ctx context.Context, h cdp.Executor) error {
return f(ctxt, h) return f(ctx, h)
} }
// Tasks is a sequential list of Actions that can be used as a single Action. // Tasks is a sequential list of Actions that can be used as a single Action.
@ -27,12 +27,12 @@ type Tasks []Action
// Do executes the list of Actions sequentially, using the provided context and // Do executes the list of Actions sequentially, using the provided context and
// frame handler. // frame handler.
func (t Tasks) Do(ctxt context.Context, h cdp.Executor) error { func (t Tasks) Do(ctx context.Context, h cdp.Executor) error {
// TODO: put individual task timeouts from context here // TODO: put individual task timeouts from context here
for _, a := range t { for _, a := range t {
// ctxt, cancel = context.WithTimeout(ctxt, timeout) // ctx, cancel = context.WithTimeout(ctx, timeout)
// defer cancel() // defer cancel()
if err := a.Do(ctxt, h); err != nil { if err := a.Do(ctx, h); err != nil {
return err return err
} }
} }
@ -46,11 +46,11 @@ func (t Tasks) Do(ctxt context.Context, h cdp.Executor) error {
// be marked for deprecation in the future, after the remaining Actions have // be marked for deprecation in the future, after the remaining Actions have
// been able to be written/tested. // been able to be written/tested.
func Sleep(d time.Duration) Action { func Sleep(d time.Duration) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
select { select {
case <-time.After(d): case <-time.After(d):
case <-ctxt.Done(): case <-ctx.Done():
return ctxt.Err() return ctx.Err()
} }
return nil return nil
}) })

View File

@ -27,7 +27,7 @@ func Evaluate(expression string, res interface{}, opts ...EvaluateOption) Action
panic("res cannot be nil") panic("res cannot be nil")
} }
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
// set up parameters // set up parameters
p := runtime.Evaluate(expression) p := runtime.Evaluate(expression)
switch res.(type) { switch res.(type) {
@ -42,7 +42,7 @@ func Evaluate(expression string, res interface{}, opts ...EvaluateOption) Action
} }
// evaluate // evaluate
v, exp, err := p.Do(ctxt, h) v, exp, err := p.Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }

View File

@ -127,7 +127,7 @@ func (t *Target) Execute(ctx context.Context, method string, params json.Marshal
// below are the old TargetHandler methods. // below are the old TargetHandler methods.
// processEvent processes an incoming event. // processEvent processes an incoming event.
func (t *Target) processEvent(ctxt context.Context, msg *cdproto.Message) error { func (t *Target) processEvent(ctx context.Context, msg *cdproto.Message) error {
if msg == nil { if msg == nil {
return ErrChannelClosed return ErrChannelClosed
} }
@ -151,7 +151,7 @@ func (t *Target) processEvent(ctxt context.Context, msg *cdproto.Message) error
case *inspector.EventDetached: case *inspector.EventDetached:
return nil return nil
case *dom.EventDocumentUpdated: case *dom.EventDocumentUpdated:
t.documentUpdated(ctxt) t.documentUpdated(ctx)
return nil return nil
} }
@ -166,7 +166,7 @@ func (t *Target) processEvent(ctxt context.Context, msg *cdproto.Message) error
// documentUpdated handles the document updated event, retrieving the document // documentUpdated handles the document updated event, retrieving the document
// root for the root frame. // root for the root frame.
func (t *Target) documentUpdated(ctxt context.Context) { func (t *Target) documentUpdated(ctx context.Context) {
f := t.cur f := t.cur
f.Lock() f.Lock()
defer f.Unlock() defer f.Unlock()
@ -178,7 +178,7 @@ func (t *Target) documentUpdated(ctxt context.Context) {
f.Nodes = make(map[cdp.NodeID]*cdp.Node) f.Nodes = make(map[cdp.NodeID]*cdp.Node)
var err error var err error
f.Root, err = dom.GetDocument().WithPierce(true).Do(ctxt, t) f.Root, err = dom.GetDocument().WithPierce(true).Do(ctx, t)
if err == context.Canceled { if err == context.Canceled {
return // TODO: perhaps not necessary, but useful to keep the tests less noisy return // TODO: perhaps not necessary, but useful to keep the tests less noisy
} }

View File

@ -27,7 +27,7 @@ func MouseAction(typ input.MouseType, x, y int64, opts ...MouseOption) Action {
// MouseClickXY sends a left mouse button click (ie, mousePressed and // MouseClickXY sends a left mouse button click (ie, mousePressed and
// mouseReleased event) at the X, Y location. // mouseReleased event) at the X, Y location.
func MouseClickXY(x, y int64, opts ...MouseOption) Action { func MouseClickXY(x, y int64, opts ...MouseOption) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
me := &input.DispatchMouseEventParams{ me := &input.DispatchMouseEventParams{
Type: input.MousePressed, Type: input.MousePressed,
X: float64(x), X: float64(x),
@ -41,13 +41,13 @@ func MouseClickXY(x, y int64, opts ...MouseOption) Action {
me = o(me) me = o(me)
} }
err := me.Do(ctxt, h) err := me.Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
me.Type = input.MouseReleased me.Type = input.MouseReleased
return me.Do(ctxt, h) return me.Do(ctx, h)
}) })
} }
@ -57,14 +57,14 @@ func MouseClickXY(x, y int64, opts ...MouseOption) Action {
// Note that the window will be scrolled if the node is not within the window's // Note that the window will be scrolled if the node is not within the window's
// viewport. // viewport.
func MouseClickNode(n *cdp.Node, opts ...MouseOption) Action { func MouseClickNode(n *cdp.Node, opts ...MouseOption) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
var pos []int var pos []int
err := EvaluateAsDevTools(fmt.Sprintf(scrollIntoViewJS, n.FullXPath()), &pos).Do(ctxt, h) err := EvaluateAsDevTools(fmt.Sprintf(scrollIntoViewJS, n.FullXPath()), &pos).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
box, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctxt, h) box, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -82,7 +82,7 @@ func MouseClickNode(n *cdp.Node, opts ...MouseOption) Action {
x /= int64(c / 2) x /= int64(c / 2)
y /= int64(c / 2) y /= int64(c / 2)
return MouseClickXY(x, y, opts...).Do(ctxt, h) return MouseClickXY(x, y, opts...).Do(ctx, h)
}) })
} }
@ -151,10 +151,10 @@ func ClickCount(n int) MouseOption {
// Please see the chromedp/kb package for implementation details and the list // Please see the chromedp/kb package for implementation details and the list
// of well-known keys. // of well-known keys.
func KeyAction(keys string, opts ...KeyOption) Action { func KeyAction(keys string, opts ...KeyOption) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
for _, r := range keys { for _, r := range keys {
for _, k := range kb.Encode(r) { for _, k := range kb.Encode(r) {
if err := k.Do(ctxt, h); err != nil { if err := k.Do(ctx, h); err != nil {
return err return err
} }
} }
@ -169,13 +169,13 @@ func KeyAction(keys string, opts ...KeyOption) Action {
// KeyActionNode dispatches a key event on a node. // KeyActionNode dispatches a key event on a node.
func KeyActionNode(n *cdp.Node, keys string, opts ...KeyOption) Action { func KeyActionNode(n *cdp.Node, keys string, opts ...KeyOption) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
err := dom.Focus().WithNodeID(n.NodeID).Do(ctxt, h) err := dom.Focus().WithNodeID(n.NodeID).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
return KeyAction(keys, opts...).Do(ctxt, h) return KeyAction(keys, opts...).Do(ctx, h)
}) })
} }

28
nav.go
View File

@ -10,8 +10,8 @@ import (
// Navigate navigates the current frame. // Navigate navigates the current frame.
func Navigate(urlstr string) Action { func Navigate(urlstr string) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
_, _, _, err := page.Navigate(urlstr).Do(ctxt, h) _, _, _, err := page.Navigate(urlstr).Do(ctx, h)
return err return err
}) })
} }
@ -23,9 +23,9 @@ func NavigationEntries(currentIndex *int64, entries *[]*page.NavigationEntry) Ac
panic("currentIndex and entries cannot be nil") panic("currentIndex and entries cannot be nil")
} }
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
var err error var err error
*currentIndex, *entries, err = page.GetNavigationHistory().Do(ctxt, h) *currentIndex, *entries, err = page.GetNavigationHistory().Do(ctx, h)
return err return err
}) })
} }
@ -38,8 +38,8 @@ func NavigateToHistoryEntry(entryID int64) Action {
// NavigateBack navigates the current frame backwards in its history. // NavigateBack navigates the current frame backwards in its history.
func NavigateBack() Action { func NavigateBack() Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
cur, entries, err := page.GetNavigationHistory().Do(ctxt, h) cur, entries, err := page.GetNavigationHistory().Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -48,14 +48,14 @@ func NavigateBack() Action {
return errors.New("invalid navigation entry") return errors.New("invalid navigation entry")
} }
return page.NavigateToHistoryEntry(entries[cur-1].ID).Do(ctxt, h) return page.NavigateToHistoryEntry(entries[cur-1].ID).Do(ctx, h)
}) })
} }
// NavigateForward navigates the current frame forwards in its history. // NavigateForward navigates the current frame forwards in its history.
func NavigateForward() Action { func NavigateForward() Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
cur, entries, err := page.GetNavigationHistory().Do(ctxt, h) cur, entries, err := page.GetNavigationHistory().Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -64,7 +64,7 @@ func NavigateForward() Action {
return errors.New("invalid navigation entry") return errors.New("invalid navigation entry")
} }
return page.NavigateToHistoryEntry(entries[cur+1].ID).Do(ctxt, h) return page.NavigateToHistoryEntry(entries[cur+1].ID).Do(ctx, h)
}) })
} }
@ -86,9 +86,9 @@ func CaptureScreenshot(res *[]byte) Action {
panic("res cannot be nil") panic("res cannot be nil")
} }
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
var err error var err error
*res, err = page.CaptureScreenshot().Do(ctxt, h) *res, err = page.CaptureScreenshot().Do(ctx, h)
return err return err
}) })
} }
@ -99,9 +99,9 @@ func CaptureScreenshot(res *[]byte) Action {
panic("id cannot be nil") panic("id cannot be nil")
} }
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error { return ActionFunc(func(ctx context.Context, h cdp.Executor) error {
var err error var err error
*id, err = page.AddScriptToEvaluateOnLoad(source).Do(ctxt, h) *id, err = page.AddScriptToEvaluateOnLoad(source).Do(ctx, h)
return err return err
}) })
} }

View File

@ -25,7 +25,7 @@ func Nodes(sel interface{}, nodes *[]*cdp.Node, opts ...QueryOption) Action {
panic("nodes cannot be nil") panic("nodes cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, n ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, n ...*cdp.Node) error {
*nodes = n *nodes = n
return nil return nil
}, opts...) }, opts...)
@ -37,7 +37,7 @@ func NodeIDs(sel interface{}, ids *[]cdp.NodeID, opts ...QueryOption) Action {
panic("nodes cannot be nil") panic("nodes cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
nodeIDs := make([]cdp.NodeID, len(nodes)) nodeIDs := make([]cdp.NodeID, len(nodes))
for i, n := range nodes { for i, n := range nodes {
nodeIDs[i] = n.NodeID nodeIDs[i] = n.NodeID
@ -51,24 +51,24 @@ func NodeIDs(sel interface{}, ids *[]cdp.NodeID, opts ...QueryOption) Action {
// Focus focuses the first node matching the selector. // Focus focuses the first node matching the selector.
func Focus(sel interface{}, opts ...QueryOption) Action { func Focus(sel interface{}, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
return dom.Focus().WithNodeID(nodes[0].NodeID).Do(ctxt, h) return dom.Focus().WithNodeID(nodes[0].NodeID).Do(ctx, h)
}, opts...) }, opts...)
} }
// Blur unfocuses (blurs) the first node matching the selector. // Blur unfocuses (blurs) the first node matching the selector.
func Blur(sel interface{}, opts ...QueryOption) Action { func Blur(sel interface{}, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
var res bool var res bool
err := EvaluateAsDevTools(fmt.Sprintf(blurJS, nodes[0].FullXPath()), &res).Do(ctxt, h) err := EvaluateAsDevTools(fmt.Sprintf(blurJS, nodes[0].FullXPath()), &res).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -87,12 +87,12 @@ func Dimensions(sel interface{}, model **dom.BoxModel, opts ...QueryOption) Acti
if model == nil { if model == nil {
panic("model cannot be nil") panic("model cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
var err error var err error
*model, err = dom.GetBoxModel().WithNodeID(nodes[0].NodeID).Do(ctxt, h) *model, err = dom.GetBoxModel().WithNodeID(nodes[0].NodeID).Do(ctx, h)
return err return err
}, opts...) }, opts...)
} }
@ -103,18 +103,18 @@ func Text(sel interface{}, text *string, opts ...QueryOption) Action {
panic("text cannot be nil") panic("text cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
return EvaluateAsDevTools(fmt.Sprintf(textJS, nodes[0].FullXPath()), text).Do(ctxt, h) return EvaluateAsDevTools(fmt.Sprintf(textJS, nodes[0].FullXPath()), text).Do(ctx, h)
}, opts...) }, opts...)
} }
// Clear clears the values of any input/textarea nodes matching the selector. // Clear clears the values of any input/textarea nodes matching the selector.
func Clear(sel interface{}, opts ...QueryOption) Action { func Clear(sel interface{}, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
@ -154,7 +154,7 @@ func Clear(sel interface{}, opts ...QueryOption) Action {
a = dom.SetNodeValue(textID, "") a = dom.SetNodeValue(textID, "")
} }
errs[i] = a.Do(ctxt, h) errs[i] = a.Do(ctx, h)
}(i, n) }(i, n)
} }
wg.Wait() wg.Wait()
@ -190,7 +190,7 @@ func Attributes(sel interface{}, attributes *map[string]string, opts ...QueryOpt
panic("attributes cannot be nil") panic("attributes cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
@ -219,7 +219,7 @@ func AttributesAll(sel interface{}, attributes *[]map[string]string, opts ...Que
panic("attributes cannot be nil") panic("attributes cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
@ -243,7 +243,7 @@ func AttributesAll(sel interface{}, attributes *[]map[string]string, opts ...Que
// SetAttributes sets the element attributes for the first node matching the // SetAttributes sets the element attributes for the first node matching the
// selector. // selector.
func SetAttributes(sel interface{}, attributes map[string]string, opts ...QueryOption) Action { func SetAttributes(sel interface{}, attributes map[string]string, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return errors.New("expected at least one element") return errors.New("expected at least one element")
} }
@ -254,7 +254,7 @@ func SetAttributes(sel interface{}, attributes map[string]string, opts ...QueryO
i++ i++
} }
return dom.SetAttributesAsText(nodes[0].NodeID, strings.Join(attrs, " ")).Do(ctxt, h) return dom.SetAttributesAsText(nodes[0].NodeID, strings.Join(attrs, " ")).Do(ctx, h)
}, opts...) }, opts...)
} }
@ -265,7 +265,7 @@ func AttributeValue(sel interface{}, name string, value *string, ok *bool, opts
panic("value cannot be nil") panic("value cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return errors.New("expected at least one element") return errors.New("expected at least one element")
} }
@ -295,24 +295,24 @@ func AttributeValue(sel interface{}, name string, value *string, ok *bool, opts
// SetAttributeValue sets the element attribute with name to value for the // SetAttributeValue sets the element attribute with name to value for the
// first node matching the selector. // first node matching the selector.
func SetAttributeValue(sel interface{}, name, value string, opts ...QueryOption) Action { func SetAttributeValue(sel interface{}, name, value string, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
return dom.SetAttributeValue(nodes[0].NodeID, name, value).Do(ctxt, h) return dom.SetAttributeValue(nodes[0].NodeID, name, value).Do(ctx, h)
}, opts...) }, opts...)
} }
// RemoveAttribute removes the element attribute with name from the first node // RemoveAttribute removes the element attribute with name from the first node
// matching the selector. // matching the selector.
func RemoveAttribute(sel interface{}, name string, opts ...QueryOption) Action { func RemoveAttribute(sel interface{}, name string, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
return dom.RemoveAttribute(nodes[0].NodeID, name).Do(ctxt, h) return dom.RemoveAttribute(nodes[0].NodeID, name).Do(ctx, h)
}, opts...) }, opts...)
} }
@ -322,25 +322,25 @@ func JavascriptAttribute(sel interface{}, name string, res interface{}, opts ...
if res == nil { if res == nil {
panic("res cannot be nil") panic("res cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
return EvaluateAsDevTools(fmt.Sprintf(attributeJS, nodes[0].FullXPath(), name), res).Do(ctxt, h) return EvaluateAsDevTools(fmt.Sprintf(attributeJS, nodes[0].FullXPath(), name), res).Do(ctx, h)
}, opts...) }, opts...)
} }
// SetJavascriptAttribute sets the javascript attribute for the first node // SetJavascriptAttribute sets the javascript attribute for the first node
// matching the selector. // matching the selector.
func SetJavascriptAttribute(sel interface{}, name, value string, opts ...QueryOption) Action { func SetJavascriptAttribute(sel interface{}, name, value string, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
var res string var res string
err := EvaluateAsDevTools(fmt.Sprintf(setAttributeJS, nodes[0].FullXPath(), name, value), &res).Do(ctxt, h) err := EvaluateAsDevTools(fmt.Sprintf(setAttributeJS, nodes[0].FullXPath(), name, value), &res).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -370,24 +370,24 @@ func InnerHTML(sel interface{}, html *string, opts ...QueryOption) Action {
// Click sends a mouse click event to the first node matching the selector. // Click sends a mouse click event to the first node matching the selector.
func Click(sel interface{}, opts ...QueryOption) Action { func Click(sel interface{}, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
return MouseClickNode(nodes[0]).Do(ctxt, h) return MouseClickNode(nodes[0]).Do(ctx, h)
}, append(opts, NodeVisible)...) }, append(opts, NodeVisible)...)
} }
// DoubleClick sends a mouse double click event to the first node matching the // DoubleClick sends a mouse double click event to the first node matching the
// selector. // selector.
func DoubleClick(sel interface{}, opts ...QueryOption) Action { func DoubleClick(sel interface{}, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
return MouseClickNode(nodes[0], ClickCount(2)).Do(ctxt, h) return MouseClickNode(nodes[0], ClickCount(2)).Do(ctx, h)
}, append(opts, NodeVisible)...) }, append(opts, NodeVisible)...)
} }
@ -397,7 +397,7 @@ func DoubleClick(sel interface{}, opts ...QueryOption) Action {
// Note: when selector matches a input[type="file"] node, then dom.SetFileInputFiles // Note: when selector matches a input[type="file"] node, then dom.SetFileInputFiles
// is used to set the upload path of the input node to v. // is used to set the upload path of the input node to v.
func SendKeys(sel interface{}, v string, opts ...QueryOption) Action { func SendKeys(sel interface{}, v string, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
@ -416,22 +416,22 @@ func SendKeys(sel interface{}, v string, opts ...QueryOption) Action {
// when working with input[type="file"], call dom.SetFileInputFiles // when working with input[type="file"], call dom.SetFileInputFiles
if n.NodeName == "INPUT" && typ == "file" { if n.NodeName == "INPUT" && typ == "file" {
return dom.SetFileInputFiles([]string{v}).WithNodeID(n.NodeID).Do(ctxt, h) return dom.SetFileInputFiles([]string{v}).WithNodeID(n.NodeID).Do(ctx, h)
} }
return KeyActionNode(n, v).Do(ctxt, h) return KeyActionNode(n, v).Do(ctx, h)
}, append(opts, NodeVisible)...) }, append(opts, NodeVisible)...)
} }
// SetUploadFiles sets the files to upload (ie, for a input[type="file"] node) // SetUploadFiles sets the files to upload (ie, for a input[type="file"] node)
// for the first node matching the selector. // for the first node matching the selector.
func SetUploadFiles(sel interface{}, files []string, opts ...QueryOption) Action { func SetUploadFiles(sel interface{}, files []string, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
return dom.SetFileInputFiles(files).WithNodeID(nodes[0].NodeID).Do(ctxt, h) return dom.SetFileInputFiles(files).WithNodeID(nodes[0].NodeID).Do(ctx, h)
}, opts...) }, opts...)
} }
@ -441,13 +441,13 @@ func Screenshot(sel interface{}, picbuf *[]byte, opts ...QueryOption) Action {
panic("picbuf cannot be nil") panic("picbuf cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
// get box model // get box model
box, err := dom.GetBoxModel().WithNodeID(nodes[0].NodeID).Do(ctxt, h) box, err := dom.GetBoxModel().WithNodeID(nodes[0].NodeID).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -459,13 +459,13 @@ func Screenshot(sel interface{}, picbuf *[]byte, opts ...QueryOption) Action {
// scroll to node position // scroll to node position
var pos []int var pos []int
err = EvaluateAsDevTools(fmt.Sprintf(scrollJS, int64(box.Margin[0]), int64(box.Margin[1])), &pos).Do(ctxt, h) err = EvaluateAsDevTools(fmt.Sprintf(scrollJS, int64(box.Margin[0]), int64(box.Margin[1])), &pos).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
// take page screenshot // take page screenshot
buf, err := page.CaptureScreenshot().Do(ctxt, h) buf, err := page.CaptureScreenshot().Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -497,13 +497,13 @@ func Screenshot(sel interface{}, picbuf *[]byte, opts ...QueryOption) Action {
// Submit is an action that submits the form of the first node matching the // Submit is an action that submits the form of the first node matching the
// selector belongs to. // selector belongs to.
func Submit(sel interface{}, opts ...QueryOption) Action { func Submit(sel interface{}, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
var res bool var res bool
err := EvaluateAsDevTools(fmt.Sprintf(submitJS, nodes[0].FullXPath()), &res).Do(ctxt, h) err := EvaluateAsDevTools(fmt.Sprintf(submitJS, nodes[0].FullXPath()), &res).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -519,13 +519,13 @@ func Submit(sel interface{}, opts ...QueryOption) Action {
// Reset is an action that resets the form of the first node matching the // Reset is an action that resets the form of the first node matching the
// selector belongs to. // selector belongs to.
func Reset(sel interface{}, opts ...QueryOption) Action { func Reset(sel interface{}, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
var res bool var res bool
err := EvaluateAsDevTools(fmt.Sprintf(resetJS, nodes[0].FullXPath()), &res).Do(ctxt, h) err := EvaluateAsDevTools(fmt.Sprintf(resetJS, nodes[0].FullXPath()), &res).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -544,12 +544,12 @@ func ComputedStyle(sel interface{}, style *[]*css.ComputedProperty, opts ...Quer
panic("style cannot be nil") panic("style cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
computed, err := css.GetComputedStyleForNode(nodes[0].NodeID).Do(ctxt, h) computed, err := css.GetComputedStyleForNode(nodes[0].NodeID).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -567,7 +567,7 @@ func MatchedStyle(sel interface{}, style **css.GetMatchedStylesForNodeReturns, o
panic("style cannot be nil") panic("style cannot be nil")
} }
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
@ -576,7 +576,7 @@ func MatchedStyle(sel interface{}, style **css.GetMatchedStylesForNodeReturns, o
ret := &css.GetMatchedStylesForNodeReturns{} ret := &css.GetMatchedStylesForNodeReturns{}
ret.InlineStyle, ret.AttributesStyle, ret.MatchedCSSRules, ret.InlineStyle, ret.AttributesStyle, ret.MatchedCSSRules,
ret.PseudoElements, ret.Inherited, ret.CSSKeyframesRules, ret.PseudoElements, ret.Inherited, ret.CSSKeyframesRules,
err = css.GetMatchedStylesForNode(nodes[0].NodeID).Do(ctxt, h) err = css.GetMatchedStylesForNode(nodes[0].NodeID).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -589,13 +589,13 @@ func MatchedStyle(sel interface{}, style **css.GetMatchedStylesForNodeReturns, o
// ScrollIntoView scrolls the window to the first node matching the selector. // ScrollIntoView scrolls the window to the first node matching the selector.
func ScrollIntoView(sel interface{}, opts ...QueryOption) Action { func ScrollIntoView(sel interface{}, opts ...QueryOption) Action {
return QueryAfter(sel, func(ctxt context.Context, h *Target, nodes ...*cdp.Node) error { return QueryAfter(sel, func(ctx context.Context, h *Target, nodes ...*cdp.Node) error {
if len(nodes) < 1 { if len(nodes) < 1 {
return fmt.Errorf("selector `%s` did not return any nodes", sel) return fmt.Errorf("selector `%s` did not return any nodes", sel)
} }
var pos []int var pos []int
err := EvaluateAsDevTools(fmt.Sprintf(scrollIntoViewJS, nodes[0].FullXPath()), &pos).Do(ctxt, h) err := EvaluateAsDevTools(fmt.Sprintf(scrollIntoViewJS, nodes[0].FullXPath()), &pos).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }

56
sel.go
View File

@ -55,7 +55,7 @@ func Query(sel interface{}, opts ...QueryOption) Action {
} }
// Do satisfies the Action interface. // Do satisfies the Action interface.
func (s *Selector) Do(ctxt context.Context, h cdp.Executor) error { func (s *Selector) Do(ctx context.Context, h cdp.Executor) error {
th, ok := h.(*Target) th, ok := h.(*Target)
if !ok { if !ok {
return ErrInvalidHandler return ErrInvalidHandler
@ -63,9 +63,9 @@ func (s *Selector) Do(ctxt context.Context, h cdp.Executor) error {
var err error var err error
select { select {
case err = <-s.run(ctxt, th): case err = <-s.run(ctx, th):
case <-ctxt.Done(): case <-ctx.Done():
err = ctxt.Err() err = ctx.Err()
} }
return err return err
@ -74,7 +74,7 @@ func (s *Selector) Do(ctxt context.Context, h cdp.Executor) error {
// run runs the selector action, starting over if the original returned nodes // run runs the selector action, starting over if the original returned nodes
// are invalidated prior to finishing the selector's by, wait, check, and after // are invalidated prior to finishing the selector's by, wait, check, and after
// funcs. // funcs.
func (s *Selector) run(ctxt context.Context, h *Target) chan error { func (s *Selector) run(ctx context.Context, h *Target) chan error {
ch := make(chan error, 1) ch := make(chan error, 1)
h.waitQueue <- func(cur *cdp.Frame) bool { h.waitQueue <- func(cur *cdp.Frame) bool {
cur.RLock() cur.RLock()
@ -86,17 +86,17 @@ func (s *Selector) run(ctxt context.Context, h *Target) chan error {
return false return false
} }
ids, err := s.by(ctxt, h, root) ids, err := s.by(ctx, h, root)
if err != nil || len(ids) < s.exp { if err != nil || len(ids) < s.exp {
return false return false
} }
nodes, err := s.wait(ctxt, h, cur, ids...) nodes, err := s.wait(ctx, h, cur, ids...)
// if nodes==nil, we're not yet ready // if nodes==nil, we're not yet ready
if nodes == nil || err != nil { if nodes == nil || err != nil {
return false return false
} }
if s.after != nil { if s.after != nil {
if err := s.after(ctxt, h, nodes...); err != nil { if err := s.after(ctx, h, nodes...); err != nil {
ch <- err ch <- err
} }
} }
@ -135,8 +135,8 @@ func ByFunc(f func(context.Context, *Target, *cdp.Node) ([]cdp.NodeID, error)) Q
// ByQuery is a query option to select a single element using // ByQuery is a query option to select a single element using
// DOM.querySelector. // DOM.querySelector.
func ByQuery(s *Selector) { func ByQuery(s *Selector) {
ByFunc(func(ctxt context.Context, h *Target, n *cdp.Node) ([]cdp.NodeID, error) { ByFunc(func(ctx context.Context, h *Target, n *cdp.Node) ([]cdp.NodeID, error) {
nodeID, err := dom.QuerySelector(n.NodeID, s.selAsString()).Do(ctxt, h) nodeID, err := dom.QuerySelector(n.NodeID, s.selAsString()).Do(ctx, h)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -151,8 +151,8 @@ func ByQuery(s *Selector) {
// ByQueryAll is a query option to select elements by DOM.querySelectorAll. // ByQueryAll is a query option to select elements by DOM.querySelectorAll.
func ByQueryAll(s *Selector) { func ByQueryAll(s *Selector) {
ByFunc(func(ctxt context.Context, h *Target, n *cdp.Node) ([]cdp.NodeID, error) { ByFunc(func(ctx context.Context, h *Target, n *cdp.Node) ([]cdp.NodeID, error) {
return dom.QuerySelectorAll(n.NodeID, s.selAsString()).Do(ctxt, h) return dom.QuerySelectorAll(n.NodeID, s.selAsString()).Do(ctx, h)
})(s) })(s)
} }
@ -165,8 +165,8 @@ func ByID(s *Selector) {
// BySearch is a query option via DOM.performSearch (works with both CSS and // BySearch is a query option via DOM.performSearch (works with both CSS and
// XPath queries). // XPath queries).
func BySearch(s *Selector) { func BySearch(s *Selector) {
ByFunc(func(ctxt context.Context, h *Target, n *cdp.Node) ([]cdp.NodeID, error) { ByFunc(func(ctx context.Context, h *Target, n *cdp.Node) ([]cdp.NodeID, error) {
id, count, err := dom.PerformSearch(s.selAsString()).Do(ctxt, h) id, count, err := dom.PerformSearch(s.selAsString()).Do(ctx, h)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -175,7 +175,7 @@ func BySearch(s *Selector) {
return []cdp.NodeID{}, nil return []cdp.NodeID{}, nil
} }
nodes, err := dom.GetSearchResults(id, 0, count).Do(ctxt, h) nodes, err := dom.GetSearchResults(id, 0, count).Do(ctx, h)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -191,9 +191,9 @@ func ByNodeID(s *Selector) {
panic("ByNodeID can only work on []cdp.NodeID") panic("ByNodeID can only work on []cdp.NodeID")
} }
ByFunc(func(ctxt context.Context, h *Target, n *cdp.Node) ([]cdp.NodeID, error) { ByFunc(func(ctx context.Context, h *Target, n *cdp.Node) ([]cdp.NodeID, error) {
for _, id := range ids { for _, id := range ids {
err := dom.RequestChildNodes(id).WithPierce(true).Do(ctxt, h) err := dom.RequestChildNodes(id).WithPierce(true).Do(ctx, h)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -205,7 +205,7 @@ func ByNodeID(s *Selector) {
// waitReady waits for the specified nodes to be ready. // waitReady waits for the specified nodes to be ready.
func (s *Selector) waitReady(check func(context.Context, *Target, *cdp.Node) error) func(context.Context, *Target, *cdp.Frame, ...cdp.NodeID) ([]*cdp.Node, error) { func (s *Selector) waitReady(check func(context.Context, *Target, *cdp.Node) error) func(context.Context, *Target, *cdp.Frame, ...cdp.NodeID) ([]*cdp.Node, error) {
return func(ctxt context.Context, h *Target, cur *cdp.Frame, ids ...cdp.NodeID) ([]*cdp.Node, error) { return func(ctx context.Context, h *Target, cur *cdp.Frame, ids ...cdp.NodeID) ([]*cdp.Node, error) {
nodes := make([]*cdp.Node, len(ids)) nodes := make([]*cdp.Node, len(ids))
cur.RLock() cur.RLock()
for i, id := range ids { for i, id := range ids {
@ -225,7 +225,7 @@ func (s *Selector) waitReady(check func(context.Context, *Target, *cdp.Node) err
wg.Add(1) wg.Add(1)
go func(i int, n *cdp.Node) { go func(i int, n *cdp.Node) {
defer wg.Done() defer wg.Done()
errs[i] = check(ctxt, h, n) errs[i] = check(ctx, h, n)
}(i, n) }(i, n)
} }
wg.Wait() wg.Wait()
@ -255,9 +255,9 @@ func NodeReady(s *Selector) {
// NodeVisible is a query option to wait until the element is visible. // NodeVisible is a query option to wait until the element is visible.
func NodeVisible(s *Selector) { func NodeVisible(s *Selector) {
WaitFunc(s.waitReady(func(ctxt context.Context, h *Target, n *cdp.Node) error { WaitFunc(s.waitReady(func(ctx context.Context, h *Target, n *cdp.Node) error {
// check box model // check box model
_, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctxt, h) _, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctx, h)
if err != nil { if err != nil {
if isCouldNotComputeBoxModelError(err) { if isCouldNotComputeBoxModelError(err) {
return ErrNotVisible return ErrNotVisible
@ -268,7 +268,7 @@ func NodeVisible(s *Selector) {
// check offsetParent // check offsetParent
var res bool var res bool
err = EvaluateAsDevTools(fmt.Sprintf(visibleJS, n.FullXPath()), &res).Do(ctxt, h) err = EvaluateAsDevTools(fmt.Sprintf(visibleJS, n.FullXPath()), &res).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -281,9 +281,9 @@ func NodeVisible(s *Selector) {
// NodeNotVisible is a query option to wait until the element is not visible. // NodeNotVisible is a query option to wait until the element is not visible.
func NodeNotVisible(s *Selector) { func NodeNotVisible(s *Selector) {
WaitFunc(s.waitReady(func(ctxt context.Context, h *Target, n *cdp.Node) error { WaitFunc(s.waitReady(func(ctx context.Context, h *Target, n *cdp.Node) error {
// check box model // check box model
_, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctxt, h) _, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctx, h)
if err != nil { if err != nil {
if isCouldNotComputeBoxModelError(err) { if isCouldNotComputeBoxModelError(err) {
return nil return nil
@ -294,7 +294,7 @@ func NodeNotVisible(s *Selector) {
// check offsetParent // check offsetParent
var res bool var res bool
err = EvaluateAsDevTools(fmt.Sprintf(visibleJS, n.FullXPath()), &res).Do(ctxt, h) err = EvaluateAsDevTools(fmt.Sprintf(visibleJS, n.FullXPath()), &res).Do(ctx, h)
if err != nil { if err != nil {
return err return err
} }
@ -307,7 +307,7 @@ func NodeNotVisible(s *Selector) {
// NodeEnabled is a query option to wait until the element is enabled. // NodeEnabled is a query option to wait until the element is enabled.
func NodeEnabled(s *Selector) { func NodeEnabled(s *Selector) {
WaitFunc(s.waitReady(func(ctxt context.Context, h *Target, n *cdp.Node) error { WaitFunc(s.waitReady(func(ctx context.Context, h *Target, n *cdp.Node) error {
n.RLock() n.RLock()
defer n.RUnlock() defer n.RUnlock()
@ -323,7 +323,7 @@ func NodeEnabled(s *Selector) {
// NodeSelected is a query option to wait until the element is selected. // NodeSelected is a query option to wait until the element is selected.
func NodeSelected(s *Selector) { func NodeSelected(s *Selector) {
WaitFunc(s.waitReady(func(ctxt context.Context, h *Target, n *cdp.Node) error { WaitFunc(s.waitReady(func(ctx context.Context, h *Target, n *cdp.Node) error {
n.RLock() n.RLock()
defer n.RUnlock() defer n.RUnlock()
@ -341,7 +341,7 @@ func NodeSelected(s *Selector) {
// matching the selector. // matching the selector.
func NodeNotPresent(s *Selector) { func NodeNotPresent(s *Selector) {
s.exp = 0 s.exp = 0
WaitFunc(func(ctxt context.Context, h *Target, cur *cdp.Frame, ids ...cdp.NodeID) ([]*cdp.Node, error) { WaitFunc(func(ctx context.Context, h *Target, cur *cdp.Frame, ids ...cdp.NodeID) ([]*cdp.Node, error) {
if len(ids) != 0 { if len(ids) != 0 {
return nil, ErrHasResults return nil, ErrHasResults
} }