Set date (x)days from now in Behat with Symfony2 forms
Using Behat i needed to be able to set a date in a form (x) number of days from the current date. This however is a problem as Behat cannot set a date (x) number of days from now as it does not know the current date. So a simple solution is to create a Behat step definition that takes the field name and a number of days. My step definition looks something like this:
And I select from "select[id^=Post_unlockedUntilDate]" a date "2" days from now
The reason i went with a CSS selector is because Behat supports this anyway, and Symfony2 can create a date form by splitting the field into 3 separate fields, for Month/Day and Year respectively. So we will need to identify 3 fields in our form. Symfony2 will label them with each with the overall field name with an additional underscore and designation. Each field will be a select field.
For example, if my field is called Post_unlockedUntilDate (which was a real field i needed this test case for [the Post_ designation came from symfony based on the entity the form related to), then the 3 fields i would need to find (as created by symfony) would be:
- Post_unlockedUntilDate_year
- Post_unlockedUntilDate_month
- Post_unlockedUntilDate_day
So i created a step definition that takes the CSS and finds the fields by the given selector. Then identifies each field in the results and assigns them to an array with a key for ‘day’, ‘month’ and ‘year’. Then all we need to do is create a new datetime object set (x) number of days from now and then apply that to each field.
/**
*
* @Given /^I select from "([^"]*)" a date "([^"]*)" days from now$/
*/
public function iSelectFromADateDaysFromNow($cssQuery, $days)
{
$items = array_map(
function ($element) {
$id = $element->getAttribute('id');
if (substr($id, strlen($id) - strlen('year'), strlen($id)) == 'year') {
$fieldName = 'year';
}
if (substr($id, strlen($id) - strlen('month'), strlen($id)) == 'month') {
$fieldName = 'month';
}
if (substr($id, strlen($id) - strlen('day'), strlen($id)) == 'day') {
$fieldName = 'day';
}
return array(
$fieldName => $element
);
},
$this->getPage()->findAll('css', $cssQuery)
);
$fields = array();
foreach ($items as $item) {
foreach ($item as $key => $field) {
$fields[$key] = $field;
}
}
WebTestCase::assertCount(3, $fields, 'Date fields could not be found!');
$date = new \Datetime('now + ' . $days . ' days');
$fields['year']->selectOption($date->format('Y'));
$fields['month']->selectOption($date->format('M'));
$fields['day']->selectOption($date->format('d'));
}
So to use it we just call:
And I select from "select[id^=Post_unlockedUntilDate]" a date "2" days from now
Hope this helps. Good luck.
Nice, one little remark “([^”]*)” allows an empty value which is not what you want.
And you can extend this this even further to:
^I select from "([^"]+)" a date "([^"]+)" from "([^"]+)"$
Which allows for a more complex pattern and starting point.
Just some idea’s.
Thanks Sebastian, so if we changed now to ‘now’ as a parameter, then it might be even better if we did this:
^I select from “([^”]+)” a date “([^”]+)”
where by the whole string for the date object constructor would look like; ‘now + 2 days’ so we would use it like:
^I select from “select[id^=Entity_field]” a date “now + 2 days”
That would be pretty flexible.
Thanks for the ideas/input Sebastian.