9

I am using Behat and Mink with the Selenium2 driver, and I'm trying to type directly into a form field (simulating raw keyboard input), instead of using the fillField() function.

This is what I'm trying:

$element = $this->getSession()->getPage()->find('css', '#questionName');
$element->focus();

$element->keyPress('a');

// also tried this, with no success
// $element->keyDown('a');
// $element->keyUp('a');

There is an <input type="text" id="questionName"> element on the page. It correctly receives the focus, but does not respond to any of the simulated keyboard input.

Is it possible to simulate raw keyboard input like this?
What am I doing wrong?

jcsanyi
  • 7,953
  • 2
  • 25
  • 51

3 Answers3

13

There seems to be a lot of posts complaining about keyPress not working as intended and some drivers don't support it at all. e.g.:

Goutte - Keyboard manipulations are not supported by Behat\Mink\Driver\GoutteDriver

The Selenium driver in particular uses a custom js library to run it's commands, however it doesn't seem to work. I've tried using both the $this->getSession()->getDriver()->keyPress() and the $element->getPress() without luck.

https://github.com/Behat/MinkSelenium2Driver/blob/master/src/Behat/Mink/Driver/Selenium2Driver.php#L815

https://github.com/Behat/MinkSelenium2Driver/blob/master/src/Behat/Mink/Driver/Selenium2/syn.js

What is interesting is that there are no unit tests for the keyPress event in the Selenium2 code base yet (so I assume it's currently in development).

So, for the moment, an adequate solution is to use the javascript emulation of key events from Is it possible to simulate key press events programmatically? (see this for an alternative if you're not using jQuery) and Behat Mink's evaluateScript function.

If you're using straight PHPUnit to test:

$key = 'a';
$script = "jQuery.event.trigger({ type : 'keypress', which : '" . $key . "' });";
$this->getSession()->evaluateScript($script);

Or if you're using Cucumber, add this to your FeatureContext.php file you can add this function:

/**
 * @Given /^(?:|I ) manually press "([^"]*)"$/
 */
public function manuallyPress($key)
{
    $script = "jQuery.event.trigger({ type : 'keypress', which : '" . $key . "' });";
    $this->getSession()->evaluateScript($script);
}

And use it in your feature file like this:

Given I manually press "a"

As for using the javascript as the solution, some of the drivers use javascript to perform the required keyPress. E.g.:

https://github.com/Behat/MinkZombieDriver/blob/master/src/Behat/Mink/Driver/ZombieDriver.php#L819

Community
  • 1
  • 1
Tom
  • 2,935
  • 1
  • 23
  • 32
1

I'm using Mink with Zombie.js and as it does not catching keyboard events natively, I both listen to focusout and keyup jQuery events.

$('form[name="order"]').find('input[id$="quantity"],input[id$="price"]').bind('keyup focusout', function(){
// [...] update order price
});

I has solved the problem for me but I didn't try it with Selenium2.

Jeremy Jumeau
  • 151
  • 1
  • 3
0

The easiest answer I have found is to trigger the key event in javascript and write a specific behat step to send the js to the browser and trigger it.

We have been using YUI so we use the YUI event simulate but jquery or native js handles it. The concept is what matters. It's the best solution I've found until the native behat support is there.

hope this helps.

public function press_key_in_the_ousupsub_editor($keys, $fieldlocator) {
        // NodeElement.keyPress simply doesn't work.
        if (!$this->running_javascript()) {
            throw new coding_exception('Selecting text requires javascript.');
        }
        // We delegate to behat_form_field class, it will
        // guess the type properly.
        $field = behat_field_manager::get_form_field_from_label($fieldlocator, $this);

        if (!method_exists($field, 'get_value')) {
            throw new coding_exception('Field does not support the get_value function.');
        }

        $editorid = $this->find_field($fieldlocator)->getAttribute('id');

        // Get query values for the range.
        $js = '
    function TriggerKeyPressBehat() {
    // http://www.wfimc.org/public/js/yui/3.4.1/docs/event/simulate.html
    YUI().use(\'node-event-simulate\', function(Y) {
        var id = "'.$editorid.'";
        var node = Y.one("#" + id + "editable");

        node.focus();
        var keyEvent = "keypress";
        if (Y.UA.webkit || Y.UA.ie) {
            keyEvent = "keydown";
        }
        // Key code (up arrow) for the keyboard shortcut which triggers this button:
        var keys =  ['.$keys.'];
        for(var i=0; i<keys.length;i++) {
            node.simulate(keyEvent, { charCode: keys[i] });
        }
    });
    }
    TriggerKeyPressBehat();';
        $this->getSession()->executeScript($js);
    }