Design, Programming, Projects, Technology

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.