sclevine / agouti

A WebDriver client and acceptance testing library for Go
MIT License
821 stars 105 forks source link

The ability to send keystrokes to the browser. #61

Open rburton opened 8 years ago

rburton commented 8 years ago

I was looking to see if the API has the ability to send keystrokes, but I was unable to locate it. Is this possible?

Sorry, I couldn't find any documentation and I've been reading through the code and API trying to locate this. It seems like I would have to implement this via the agouti.Session and the JSON protocol.

sclevine commented 8 years ago

Hi @rburton,

There are a few ways to do this:

keystrokes := map[string][]string{"value": {"some keystrokes"}}
page.Session().Send("POST", "keys", keystrokes, nil)

Let me know if the third case is what you're looking for. It should eventually be exposed with page.Session().Keys(values string), and adding that method is trivial.

Hope this helps! Stephen

rburton commented 8 years ago

The latter is exactly what I was looking to do. In fact, I created a function called SendKeys that does exactly what you just provided.

One other request is around the ability to wait for elements to be visible. I noticed there's a recommendation in using http://onsi.github.io/gomega/#making-asynchronous-assertions but what I'm actually looking for is more on the lines to pause the execution until either a timeout period is reached or the element is displayed.

In Java using RemoteWebDriver they have WebDriverWait and you would do something like

wait.until(presenceOfAllElementsLocatedBy(cssSelector("#name")));

One more last question :) It would be very powerful to obtain the PID of the PhantomJS process that's running so users could check to see how much memory the process is using. Overtime, Phantom.js tends to grow in memory usage, so it would be awesome to check the memory size and restart the process if it starts to exceed a certain amount of memory.

Keep up the great work.

sclevine commented 8 years ago

Done (6bebd2095b2936ea00539be8b0971cc9eeaddc72). I've seen most people use the Value() method for this, but I'm happy to make the API more complete.

If you want to wait for an element to become visible on the page with a provided timeout, use the Agouti BeVisible matcher with Gomega's Eventually like this:

import (
    ...
    . "github.com/sclevine/agouti/matchers"
    . "github.com/onsi/gomega"
    ...
)
...
Eventually(page.Find("#my_element"), "100s").Should(BeVisible()) 

If you only care about DOM presence:

Eventually(page.Find("#my_element"), "100s").Should(BeFound()) 

Exposing the PID of the api.WebDriver process should be relatively straightforward. The agouti/api/internal/service.Service.Start() method could return the PID from the *exec.Cmd, and we could store it on the api.WebDriver. I can do this when I have more time, but feel free to open a PR :).

Thanks! Stephen

rburton commented 8 years ago

I'll take the information you provided and work on a push request.

In addition, I'm going to work on a way to pass cli options to Phantom.js so a user can avoid loading imagines for instance.

mattetti commented 8 years ago

Just a quick note that we also use the Keys function, note that you might want to make the special key codes available directly in Agouti:

const (
    NULL            = "\uE000"
    CANCEL          = "\uE001"
    HELP            = "\uE002"
    BACK_SPACE      = "\uE003"
    TAB             = "\uE004"
    CLEAR           = "\uE005"
    RETURN          = "\uE006"
    ENTER           = "\uE007"
    SHIFT           = "\uE008"
    LEFT_SHIFT      = "\uE008"
    CONTROL         = "\uE009"
    LEFT_CONTROL    = "\uE009"
    ALT             = "\uE00A"
    LEFT_ALT        = "\uE00A"
    PAUSE           = "\uE00B"
    ESCAPE          = "\uE00C"
    SPACE           = "\uE00D"
    PAGE_UP         = "\uE00E"
    PAGE_DOWN       = "\uE00F"
    END             = "\uE010"
    HOME            = "\uE011"
    LEFT            = "\uE012"
    ARROW_LEFT      = "\uE012"
    UP              = "\uE013"
    ARROW_UP        = "\uE013"
    RIGHT           = "\uE014"
    ARROW_RIGHT     = "\uE014"
    DOWN            = "\uE015"
    ARROW_DOWN      = "\uE015"
    INSERT          = "\uE016"
    DELETE          = "\uE017"
    SEMICOLON       = "\uE018"
    EQUALS          = "\uE019"
    NUMPAD0         = "\uE01A"
    NUMPAD1         = "\uE01B"
    NUMPAD2         = "\uE01C"
    NUMPAD3         = "\uE01D"
    NUMPAD4         = "\uE01E"
    NUMPAD5         = "\uE01F"
    NUMPAD6         = "\uE020"
    NUMPAD7         = "\uE021"
    NUMPAD8         = "\uE022"
    NUMPAD9         = "\uE023"
    MULTIPLY        = "\uE024"
    ADD             = "\uE025"
    SEPARATOR       = "\uE026"
    SUBTRACT        = "\uE027"
    DECIMAL         = "\uE028"
    DIVIDE          = "\uE029"
    F1              = "\uE031"
    F2              = "\uE032"
    F3              = "\uE033"
    F4              = "\uE034"
    F5              = "\uE035"
    F6              = "\uE036"
    F7              = "\uE037"
    F8              = "\uE038"
    F9              = "\uE039"
    F10             = "\uE03A"
    F11             = "\uE03B"
    F12             = "\uE03C"
    META            = "\uE03D"
    COMMAND         = "\uE03D"
    ZENKAKU_HANKAKU = "\uE040"
)
cakesmith commented 6 years ago

Is there a way to send chords, or a keydown/keyup? For example I want to send Ctrl + t to open a new tab, but it seems that this isn't quite working

ctrl := "\uE009"
err = page.Find("body").SendKeys(ctrl + "t")