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.