From 66dbfadd2de9fc564906085fd35d0ecd4d946821 Mon Sep 17 00:00:00 2001 From: "Eloy Lafuente (stronk7)" Date: Sat, 3 Apr 2021 10:33:57 +0200 Subject: [PATCH] MDL-71264 behat: Change date(time) element update order This includes 2 change to the order date(time) elements are filled, each one addressing one type of problem, where current order is problematic and can lead to unexpected dates. 1) Changing date, when current month only has X days and target month has more than X days. Example, being 1 April, change the date to 31 May. This is solved by changing the order of introduction from current D => M => Y to Y => M => D. 2) Changing date, when target month only has X days and current month has more that X days. Example, being 31 March, change the date to 28 Feb. This is solved by always setting the D to 1, before the Y => M => D sequence commented @ 1) begins. --- lib/behat/form_field/behat_form_date.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/behat/form_field/behat_form_date.php b/lib/behat/form_field/behat_form_date.php index 010b5aaffc86f..030d8525992e1 100644 --- a/lib/behat/form_field/behat_form_date.php +++ b/lib/behat/form_field/behat_form_date.php @@ -56,6 +56,14 @@ public function set_value($value) { // Disable the given date selector field. $this->set_child_field_value('enabled', false); } else if (is_numeric($value)) { // The value is numeric (unix timestamp). + // First, reset the day always to an existing one (1st). Without that + // undesired modifications (JS) happens when changing of month and day if + // the interim combination doesn't exists (for example, 31 March => 01 April). + // Note that instead of always setting the day to 1, this could be a little more + // clever, for example only changing when the day > 28, or only when the + // months (current or changed) have less days that the other. But that would + // require more complex calculations than the simpler line below. + $this->set_child_field_value('day', 1); // Assign the mapped values to each form element in the date selector field. foreach ($this->get_mapped_fields($value) as $childname => $childvalue) { $this->set_child_field_value($childname, $childvalue); @@ -74,11 +82,18 @@ public function set_value($value) { * @return array */ protected function get_mapped_fields(int $timestamp): array { + // Order is important, first enable, and then year -> month -> day + // (other order can lead to some transitions not working as expected, + // for example, changing from 15 June to 31 August, Behat ends with + // date being 1 August if the modification order is day, then month). + // Note that the behaviour described above is 100% reproducible + // manually, with the form (JS) auto-fixing things in the middle and + // leading to undesired final dates. return [ 'enabled' => true, - 'day' => date('j', $timestamp), - 'month' => date('n', $timestamp), 'year' => date('Y', $timestamp), + 'month' => date('n', $timestamp), + 'day' => date('j', $timestamp), ]; }