Dev Blog

When working with form fields, Codeception has already prepared tools to fill-in required data. However modern applications often works on editable elements via contenteditable attribute.
This approach has advantage of having visual HTML right away editable. When running in-browser acceptance tests, it is required to fill-in those values too. This can be done with Facebook WebDriver package, included in main codeception package.

Using sendKeys

To allow writing into arbitrary element, or make it react on key events, WebDriver exposes sendKeys method which will send keystrokes like if it were typed on keyboard. Recommended way to add this functionality is to add methods to codeception's generated AcceptanceTester class, which can be found in tests/_support folder.

To get instance of WebDriver, there is a method of AcceptanceTester to execute action in Selenium via WebDriver, taking as argument callable, which will have passed WebDriver instance as a parameter. Resulting code is pretty simple, but possibly not obvious.

Type Text method

Example code to send arbitrary text to active element. See class generated in tests/_support:

<?php
class AcceptanceTester extends Actor
{

use AcceptanceTesterActions;

public function type($text)
{
$I = $this;
$I->executeInSelenium(function(RemoteWebDriver $webDriver)use($text)
{
$webDriver->getKeyboard()->sendKeys($text);
});
}
}

Using in tests

Now having this method we can send keys to active element. To activate element, simply execute click on it and then call type:

<?php
use AcceptanceTester;

class MyCest
{
public function tryToWrite(AcceptanceTester $I)
{
$I->click('#myEditableElement');
$I->type('Input Text');
}
}

Clearing text

Using this method, it is possible to write text, but if there is already text in it, it will be appended. To clear text, we will use again a WebDriver, but this time it's sub object Action, which allows fine grained keyboard interaction. Action methods allows us to control whether key is pressed or released. First we define keys sequence, when sequence is finished, we call perform method to send it to browser. It has fluid interface, so method chaining can be used.

To mimic real user interaction, we will select all with ctrl+a keyboard shortcut and then press delete key.

A new method will be added to AcceptanceTester:

<?php
public function clearText()
{
$I = $this;
$I->executeInSelenium(function(RemoteWebDriver $webDriver)use($I)
{
$action = $webDriver->action();
$action->keyDown(null, WebDriverKeys::CONTROL)
->keyDown(null, 'a')
->keyUp(null, 'a')
->keyUp(null, WebDriverKeys::CONTROL)
->keyUp(null, WebDriverKeys::DELETE)
->keyDown(null, WebDriverKeys::DELETE)
->perform();
});
}

Clearing text in tests

To ensure that input is empty before we send keys, clear it first:

<?php
use AcceptanceTester;

class MyCest
{
public function tryToWrite(AcceptanceTester $I)
{
$I->click('#myEditableElement');
$I->clearText();
$I->type('Input Text');
}
}