Skip to content

Commit

Permalink
Update to gcd protocol.json 1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
wirepair committed Apr 14, 2017
1 parent a1236d0 commit 36df25a
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 35 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Autogcd is a wrapper around the [gcd](https://github.com/wirepair/gcd/) library to enable automation of Google Chrome. It some what mimics the functionality offered by WebDriver but allows more low level access via the debugger service.

## Changelog
April 2017: Updated to latest gcd / protocol.json file. Fixed unit tests to wait for stability a bit longer as node changes seem to take longer than before.
June 2016: Updated to latest gcd / protocol.json file. Fixed calls to Network.Enable to take in the required buffer sizes.

## Dependencies
Expand Down
36 changes: 19 additions & 17 deletions api_overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,54 +37,56 @@ work.
*/

// Evaluate - Evaluates expression on global object.
// This method is overriden because the docs lie, passing 0 returns invalid context id, we must remove it from the map
// entirely for the call to work on the global object.
// expression - Expression to evaluate.
// objectGroup - Symbolic group name that can be used to release multiple objects.
// includeCommandLineAPI - Determines whether Command Line API should be available during the evaluation.
// doNotPauseOnExceptionsAndMuteConsole - Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state.
// contextId - Specifies in which isolated context to perform evaluation. Each content script lives in an isolated context and this parameter may be used to specify one of those contexts. If the parameter is omitted or 0 the evaluation will be performed in the context of the inspected page.
// silent - In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides <code>setPauseOnException</code> state.
// contextId - Specifies in which execution context to perform evaluation. If the parameter is omitted the evaluation will be performed in the context of the inspected page.
// returnByValue - Whether the result is expected to be a JSON object that should be sent by value.
// generatePreview - Whether preview should be generated for the result.
// Returns - result - Evaluation result. wasThrown - True if the result was thrown during the evaluation. exceptionDetails - Exception details.
func overridenRuntimeEvaluate(target *gcd.ChromeTarget, expression string, objectGroup string, includeCommandLineAPI bool, doNotPauseOnExceptionsAndMuteConsole bool, contextId int, returnByValue bool, generatePreview bool) (*gcdapi.RuntimeRemoteObject, bool, *gcdapi.RuntimeExceptionDetails, error) {
paramRequest := make(map[string]interface{}, 7)
// userGesture - Whether execution should be treated as initiated by user in the UI.
// awaitPromise - Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error.
// Returns - result - Evaluation result. exceptionDetails - Exception details.
func overridenRuntimeEvaluate(target *gcd.ChromeTarget, expression string, objectGroup string, includeCommandLineAPI bool, silent bool, contextId int, returnByValue bool, generatePreview bool, userGesture bool, awaitPromise bool) (*gcdapi.RuntimeRemoteObject, *gcdapi.RuntimeExceptionDetails, error) {
paramRequest := make(map[string]interface{}, 9)
paramRequest["expression"] = expression
paramRequest["objectGroup"] = objectGroup
paramRequest["includeCommandLineAPI"] = includeCommandLineAPI
paramRequest["doNotPauseOnExceptionsAndMuteConsole"] = doNotPauseOnExceptionsAndMuteConsole
paramRequest["silent"] = silent
// only add context id if it's non-zero
if contextId != 0 {
paramRequest["contextId"] = contextId
}
paramRequest["returnByValue"] = returnByValue
paramRequest["generatePreview"] = generatePreview
paramRequest["userGesture"] = userGesture
paramRequest["awaitPromise"] = awaitPromise
resp, err := gcdmessage.SendCustomReturn(target, target.GetSendCh(), &gcdmessage.ParamRequest{Id: target.GetId(), Method: "Runtime.evaluate", Params: paramRequest})
if err != nil {
return nil, false, nil, err
}

if resp == nil {
return nil, false, nil, &gcdmessage.ChromeEmptyResponseErr{}
return nil, nil, err
}

var chromeData struct {
Result struct {
Result *gcdapi.RuntimeRemoteObject
WasThrown bool
ExceptionDetails *gcdapi.RuntimeExceptionDetails
}
}

if resp == nil {
return nil, nil, &gcdmessage.ChromeEmptyResponseErr{}
}

// test if error first
cerr := &gcdmessage.ChromeErrorResponse{}
json.Unmarshal(resp.Data, cerr)
if cerr != nil && cerr.Error != nil {
return nil, false, nil, &gcdmessage.ChromeRequestErr{Resp: cerr}
return nil, nil, &gcdmessage.ChromeRequestErr{Resp: cerr}
}

if err := json.Unmarshal(resp.Data, &chromeData); err != nil {
return nil, false, nil, err
return nil, nil, err
}

return chromeData.Result.Result, chromeData.Result.WasThrown, chromeData.Result.ExceptionDetails, nil
return chromeData.Result.Result, chromeData.Result.ExceptionDetails, nil
}
3 changes: 2 additions & 1 deletion element.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ func (e *Element) GetSource() (string, error) {
if e.invalidated {
return "", &InvalidElementErr{}
}
e.tab.debugf("id: %d\n", id)
return e.tab.DOM.GetOuterHTML(id)
}

Expand Down Expand Up @@ -270,7 +271,7 @@ func (e *Element) GetEventListeners() ([]*gcdapi.DOMDebuggerEventListener, error
if err != nil {
return nil, err
}
eventListeners, err := e.tab.DOMDebugger.GetEventListeners(rro.ObjectId)
eventListeners, err := e.tab.DOMDebugger.GetEventListeners(rro.ObjectId, 1, false)
if err != nil {
return nil, err
}
Expand Down
24 changes: 17 additions & 7 deletions element_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func TestElementClick(t *testing.T) {
}()

wg.Wait()
timeout.Stop()
}

func TestElementMouseOver(t *testing.T) {
Expand All @@ -128,11 +129,11 @@ func TestElementMouseOver(t *testing.T) {
if err != nil {
t.Fatalf("Error navigating: %s\n", err)
}
/*
err = tab.WaitFor(testWaitRate, testWaitTimeout, ElementByIdReady(tab, "button"))
if err != nil {
t.Fatalf("error finding buttons, timed out waiting: %s\n", err)
}*/

err = tab.WaitFor(testWaitRate, testWaitTimeout, ElementByIdReady(tab, "button"))
if err != nil {
t.Fatalf("error finding buttons, timed out waiting: %s\n", err)
}

button, _, err := tab.GetElementById("button")
if err != nil {
Expand All @@ -153,6 +154,7 @@ func TestElementMouseOver(t *testing.T) {
}()

wg.Wait()
timeout.Stop()
}

func TestElementDoubleClick(t *testing.T) {
Expand Down Expand Up @@ -204,6 +206,7 @@ func TestElementDoubleClick(t *testing.T) {
}(timeout)

wg.Wait()
timeout.Stop()
}

func TestElementGetSource(t *testing.T) {
Expand Down Expand Up @@ -477,7 +480,7 @@ func TestElementGetEventListeners(t *testing.T) {
listeners, err := ele.GetEventListeners()
for _, listener := range listeners {
//t.Logf("%#v\n", listener)
_, err := tab.GetScriptSource(listener.Location.ScriptId)
_, err := tab.GetScriptSource(listener.ScriptId)
if err != nil {
t.Fatalf("error getting source: %s\n", err)
}
Expand Down Expand Up @@ -545,6 +548,8 @@ func TestElementFrameSet(t *testing.T) {
t.Fatalf("error getting tab")
}

//tab.Debug(true)

_, err = tab.Navigate(testServerAddr + "frameset.html")
if err != nil {
t.Fatalf("Error navigating: %s\n", err)
Expand All @@ -557,10 +562,15 @@ func TestElementFrameSet(t *testing.T) {
if frs == nil {
t.Fatalf("error getting frames, because nil\n")
}
t.Logf("# of frames: %d\n", len(frs))
for _, fr := range frs {
fr.WaitForReady()
if fr.IsInvalid() {
continue
}
str, err := fr.GetSource()
if err != nil {
t.Fatalf("error getting source: %s\n", err)
t.Logf("error getting source: %s\n", err)
}
var isDoc bool
isDoc, err = fr.IsDocument()
Expand Down
27 changes: 19 additions & 8 deletions tab.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ func (t *Tab) Navigate(url string) (string, error) {
t.setIsNavigating(false)
}()

frameId, err := t.Page.Navigate(url)
frameId, err := t.Page.Navigate(url, "")
if err != nil {
return "", err
}
Expand Down Expand Up @@ -497,7 +497,7 @@ func (t *Tab) GetScriptSource(scriptId string) (string, error) {
// the page has loaded, it creates new nodeIds and all functions that look up elements (QuerySelector)
// will fail.
func (t *Tab) getDocument() (*Element, error) {
doc, err := t.DOM.GetDocument()
doc, err := t.DOM.GetDocument(-1, false)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -540,7 +540,7 @@ func (t *Tab) GetElementByNodeId(nodeId int) (*Element, bool) {

// Returns the element given the x, y coordinates on the page, or returns error.
func (t *Tab) GetElementByLocation(x, y int) (*Element, error) {
nodeId, err := t.DOM.GetNodeForLocation(x, y)
nodeId, err := t.DOM.GetNodeForLocation(x, y, false)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -801,17 +801,28 @@ func (t *Tab) RemoveScriptFromOnLoad(scriptId string) error {

// Evaluates script in the global context.
func (t *Tab) EvaluateScript(scriptSource string) (*gcdapi.RuntimeRemoteObject, error) {
return t.evaluateScript(scriptSource, false)
}

// Evaluates script in the global context.
func (t *Tab) EvaluatePromiseScript(scriptSource string) (*gcdapi.RuntimeRemoteObject, error) {
return t.evaluateScript(scriptSource, true)
}

// Evaluates script in the global context.
func (t *Tab) evaluateScript(scriptSource string, awaitPromise bool) (*gcdapi.RuntimeRemoteObject, error) {
objectGroup := "autogcd"
includeCommandLineAPI := true
doNotPauseOnExceptionsAndMuteConsole := true
contextId := 0
silent := true
returnByValue := true
generatePreview := true
rro, thrown, exception, err := overridenRuntimeEvaluate(t.ChromeTarget, scriptSource, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, contextId, returnByValue, generatePreview)
userGestures := true
rro, exception, err := overridenRuntimeEvaluate(t.ChromeTarget, scriptSource, objectGroup, includeCommandLineAPI, silent, contextId, returnByValue, generatePreview, userGestures, awaitPromise)
if err != nil {
return nil, err
}
if thrown || exception != nil {
if exception != nil {
return nil, &ScriptEvaluationErr{Message: "error executing script: ", ExceptionText: exception.Text, ExceptionDetails: exception}
}
return rro, nil
Expand All @@ -820,7 +831,7 @@ func (t *Tab) EvaluateScript(scriptSource string) (*gcdapi.RuntimeRemoteObject,
// Takes a screenshot of the currently loaded page (only the dimensions visible in browser window)
func (t *Tab) GetScreenShot() ([]byte, error) {
var imgBytes []byte
img, err := t.Page.CaptureScreenshot()
img, err := t.Page.CaptureScreenshot("png", 0, false)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1287,7 +1298,7 @@ func (t *Tab) documentUpdated() {

// Ask the debugger service for child nodes.
func (t *Tab) requestChildNodes(nodeId, depth int) {
_, err := t.DOM.RequestChildNodes(nodeId, depth)
_, err := t.DOM.RequestChildNodes(nodeId, depth, false)
if err != nil {
t.debugf("error requesting child nodes: %s\n", err)
}
Expand Down
18 changes: 16 additions & 2 deletions tab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ func TestTabGetCurrentUrl(t *testing.T) {
if _, err := tab.Navigate(testServerAddr + "console.html?x=1"); err != nil {
t.Fatalf("Error navigating: %s\n", err)
}
tab.WaitStable()

url, err := tab.GetCurrentUrl()
if err != nil {
t.Fatalf("error getting url: %s\n", err)
Expand Down Expand Up @@ -108,6 +110,8 @@ func TestTabGetPageSource(t *testing.T) {
if _, err := tab.Navigate(testServerAddr + "inner.html"); err != nil {
t.Fatalf("Error navigating: %s\n", err)
}
tab.WaitStable()

ele, err := tab.GetDocument()
if err != nil {
t.Fatalf("error getting tab document")
Expand Down Expand Up @@ -385,6 +389,8 @@ func TestTabWindows(t *testing.T) {
if _, err := tab.Navigate(testServerAddr + "window_main.html"); err != nil {
t.Fatalf("error opening first window")
}
tab.WaitStable()

t.Logf("# of elements: %d\n", len(tab.elements))
ele, _, err := tab.GetElementById("mainwindow")
if err != nil {
Expand Down Expand Up @@ -417,6 +423,8 @@ func TestTabAfterRedirect(t *testing.T) {
t.Fatalf("error opening first window")
}

tab.WaitStable()

url, err := tab.GetCurrentUrl()
if err != nil {
t.Fatalf("error getting url: %s\n", err)
Expand Down Expand Up @@ -523,6 +531,8 @@ func TestTabFrameRedirect(t *testing.T) {
t.Fatalf("error opening first window")
}

tab.WaitStable()

ifr, ready, err := tab.GetElementById("frameredirect")
if err != nil {
t.Fatalf("error finding frame element")
Expand All @@ -543,11 +553,13 @@ func TestTabFrameRedirect(t *testing.T) {
}
ifrDoc, _ := tab.GetElementByNodeId(ifrDocNodeId)

ifrDoc.WaitForReady()

// wait for setTimeout redirect
time.Sleep(4 * time.Second)
time.Sleep(6 * time.Second)

if !ifr.IsInvalid() {
t.Fatalf("error iframe was not invalidated after redirect")
t.Fatalf("error iframe was not invalidated after redirect: %d\n", ifr.NodeId())
}

if !ifrDoc.IsInvalid() {
Expand Down Expand Up @@ -723,6 +735,8 @@ func testMultiNavigateSendKeys(t *testing.T, wg *sync.WaitGroup, tab *Tab) {
t.Fatalf("Error navigating: %s\n", err)
}

tab.WaitStable()

ele, _, err = tab.GetElementById("attr")
if err != nil {
t.Fatalf("error finding input attr: %s\n", err)
Expand Down

0 comments on commit 36df25a

Please sign in to comment.