MDL-43738 behat: Refactoring the field type guesser
authorDavid Monllao <davidm@moodle.com>
Thu, 27 Feb 2014 08:39:25 +0000 (16:39 +0800)
committerDavid Monllao <davidm@moodle.com>
Thu, 27 Feb 2014 10:43:20 +0000 (18:43 +0800)
The previous behaviour delegates the responsability
of overwriting the 3 public methods to the child
classes, now the field type or moodleform field is
guessed earlier in the execution flow.

Other changes introduced here:
- Fix wrong moodleform detection when there is a form
  in the page but the field we are dealing with is
  not inside it.
- Updating the last week feature files to these new
  step definitions.
- Some coding style changes.

13 files changed:
lib/behat/behat_field_manager.php
lib/behat/form_field/behat_form_date_selector.php
lib/behat/form_field/behat_form_editor.php
lib/behat/form_field/behat_form_field.php
lib/behat/form_field/behat_form_group.php
lib/behat/form_field/behat_form_modvisible.php
lib/behat/form_field/behat_form_radio.php
lib/behat/form_field/behat_form_select.php
lib/behat/form_field/behat_form_selectyesno.php
lib/behat/form_field/behat_form_text.php [new file with mode: 0644]
lib/behat/form_field/behat_form_textarea.php [new file with mode: 0644]
mod/quiz/tests/behat/add_quiz.feature
mod/quiz/tests/behat/behat_mod_quiz.php

index b83b18e..7454da8 100644 (file)
@@ -80,9 +80,16 @@ class behat_field_manager {
 
         global $CFG;
 
+        // If the field is not part of a moodleform, we should still try to find out
+        // which field type are we dealing with.
+        if ($type == 'field' &&
+                $guessedtype = self::guess_field_type($fieldnode, $session)) {
+            $type = $guessedtype;
+        }
+
         $classname = 'behat_form_' . $type;
 
-        // Fallsback on the default form field if nothing specific exists.
+        // Fallsback on the type guesser if nothing specific exists.
         $classpath = $CFG->libdir . '/behat/form_field/' . $classname . '.php';
         if (!file_exists($classpath)) {
             $classname = 'behat_form_field';
@@ -94,6 +101,58 @@ class behat_field_manager {
         return new $classname($session, $fieldnode);
     }
 
+    /**
+     * Guesses a basic field type and returns it.
+     *
+     * This method is intended to detect HTML form fields when no
+     * moodleform-specific elements have been detected.
+     *
+     * @param NodeElement $fieldnode
+     * @param Session $session
+     * @return string|bool The field type or false.
+     */
+    public static function guess_field_type(NodeElement $fieldnode, Session $session) {
+
+        // Textareas are considered text based elements.
+        $tagname = strtolower($fieldnode->getTagName());
+        if ($tagname == 'textarea') {
+
+            // If there is an iframe with $id + _ifr there a TinyMCE editor loaded.
+            $xpath = '//iframe[@id="' . $fieldnode->getAttribute('id') . '_ifr"]';
+            if ($session->getPage()->find('xpath', $xpath)) {
+                return 'editor';
+            }
+            return 'textarea';
+
+        } else if ($tagname == 'input') {
+            $type = $fieldnode->getAttribute('type');
+            switch ($type) {
+                case 'text':
+                case 'password':
+                case 'email':
+                case 'file':
+                    return 'text';
+                case 'checkbox':
+                    return 'checkbox';
+                    break;
+                case 'radio':
+                    return 'radio';
+                    break;
+                default:
+                    // Here we return false because all text-based
+                    // fields should be included in the first switch case.
+                    return false;
+            }
+
+        } else if ($tagname == 'select') {
+            // Select tag.
+            return 'select';
+        }
+
+        // We can not provide a closer field type.
+        return false;
+    }
+
     /**
      * Detects when the field is a moodleform field type.
      *
@@ -108,7 +167,10 @@ class behat_field_manager {
     protected static function is_moodleform_field(NodeElement $fieldnode) {
 
         // We already waited when getting the NodeElement and we don't want an exception if it's not part of a moodleform.
-        $parentformfound = $fieldnode->find('xpath', "/ancestor::form[contains(concat(' ', normalize-space(@class), ' '), ' mform ')]/fieldset");
+        $parentformfound = $fieldnode->find('xpath',
+            "/ancestor::fieldset" .
+            "/ancestor::form[contains(concat(' ', normalize-space(@class), ' '), ' mform ')]"
+        );
 
         return ($parentformfound != false);
     }
index 4fc8e47..71c477c 100644 (file)
@@ -30,9 +30,6 @@ require_once(__DIR__  . '/behat_form_group.php');
 /**
  * Date form field.
  *
- * Simple extension of behat_form_group to allow the different
- * date_selector fields to be filled according to it's type.
- *
  * This class will be refactored in case we are interested in
  * creating more complex formats to fill date and date-time fields.
  *
index 4f100ac..b97976a 100644 (file)
@@ -27,7 +27,7 @@
 
 use Behat\Mink\Element\NodeElement as NodeElement;
 
-require_once(__DIR__ . '/behat_form_field.php');
+require_once(__DIR__ . '/behat_form_textarea.php');
 
 /**
  * Moodle editor field.
@@ -38,7 +38,7 @@ require_once(__DIR__ . '/behat_form_field.php');
  * @copyright 2012 David Monllaó
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class behat_form_editor extends behat_form_field {
+class behat_form_editor extends behat_form_textarea {
 
     /**
      * Sets the value to a field.
index aca068f..4d3f1b4 100644 (file)
@@ -69,14 +69,11 @@ class behat_form_field {
      * @return void
      */
     public function set_value($value) {
-
-        // If we are not dealing with a text-based tag try to find the most appropiate
-        // behat_form_* class to deal with it.
-        if ($instance = $this->guess_type()) {
-            $instance->set_value($value);
-        } else {
-            $this->field->setValue($value);
-        }
+        // We delegate to the best guess, if we arrived here
+        // using the generic behat_form_field is because we are
+        // dealing with a fgroup element.
+        $instance = $this->guess_type();
+        return $instance->set_value($value);
     }
 
     /**
@@ -85,14 +82,11 @@ class behat_form_field {
      * @return string
      */
     public function get_value() {
-
-        // If we are not dealing with a text-based tag try to find the most appropiate
-        // behat_form_* class to deal with it.
-        if ($instance = $this->guess_type()) {
-            return $instance->get_value();
-        } else {
-            return $this->field->getValue();
-        }
+        // We delegate to the best guess, if we arrived here
+        // using the generic behat_form_field is because we are
+        // dealing with a fgroup element.
+        $instance = $this->guess_type();
+        return $instance->get_value();
     }
 
     /**
@@ -105,18 +99,11 @@ class behat_form_field {
      * @return bool The provided value matches the field value?
      */
     public function matches($expectedvalue) {
-
-        // If we are not dealing with a text-based tag try to find the most appropiate
-        // behat_form_* class to deal with it.
-        if ($instance = $this->guess_type()) {
-            return $instance->matches($expectedvalue);
-        }
-
-        // Text-based comparison.
-        if (trim($expectedvalue) != trim($this->get_value())) {
-            return false;
-        }
-        return true;
+        // We delegate to the best guess, if we arrived here
+        // using the generic behat_form_field is because we are
+        // dealing with a fgroup element.
+        $instance = $this->guess_type();
+        return $instance->matches($expectedvalue);
     }
 
     /**
@@ -130,53 +117,17 @@ class behat_form_field {
      * moodle form elements we will need to refactor this simple HTML elements
      * guess method.
      *
-     * @return mixed False if no need for an special behat_form_*, otherwise the behat_form_*
+     * @return behat_form_field
      */
     private function guess_type() {
         global $CFG;
 
-        // Textareas are considered text based elements.
-        $tagname = strtolower($this->field->getTagName());
-        if ($tagname == 'textarea') {
-
-            if (!$this->running_javascript()) {
-                return false;
-            }
-
-            // If there is an iframe with $id + _ifr there a TinyMCE editor loaded.
-            $xpath = '//iframe[@id="' . $this->field->getAttribute('id') . '_ifr"]';
-            if (!$this->session->getPage()->find('xpath', $xpath)) {
-
-                // Generic one if it is a normal textarea.
-                return false;
-            }
-
-            $classname = 'behat_form_editor';
-
-        } else if ($tagname == 'input') {
-            $type = $this->field->getAttribute('type');
-            switch ($type) {
-                case 'text':
-                    return false;
-                case 'checkbox':
-                    $classname = 'behat_form_checkbox';
-                    break;
-                case 'radio':
-                    $classname = 'behat_form_radio';
-                    break;
-                default:
-                    return false;
-            }
-
-        } else if ($tagname == 'select') {
-            // Select tag.
-            $classname = 'behat_form_select';
-
-        } else {
-            // We can not provide a closer field type.
-            return false;
+        // We default to the text-based field if nothing was detected.
+        if (!$type = behat_field_manager::guess_field_type($this->field, $this->session)) {
+            $type = 'text';
         }
 
+        $classname = 'behat_form_' . $type;
         $classpath = $CFG->dirroot . '/lib/behat/form_field/' . $classname . '.php';
         require_once($classpath);
         return new $classname($this->session, $this->field);
@@ -205,10 +156,19 @@ class behat_form_field {
             throw new coding_exception('You can only get an internal ID using the selenium driver.');
         }
 
-        return $this->session->
-            getDriver()->
-            getWebDriverSession()->
-            element('xpath', $this->field->getXPath())->
-            getID();
+        return $this->session->getDriver()->getWebDriverSession()->element('xpath', $this->field->getXPath())->getID();
+    }
+
+    /**
+     * Checks if the provided text matches the field value.
+     *
+     * @param string $expectedvalue
+     * @return bool
+     */
+    protected function text_matches($expectedvalue) {
+        if (trim($expectedvalue) != trim($this->get_value())) {
+            return false;
+        }
+        return true;
     }
 }
index 533a787..3e8b2e5 100644 (file)
@@ -30,8 +30,9 @@ require_once(__DIR__  . '/behat_form_field.php');
 /**
  * Class to re-guess the field type as grouped fields can have different field types.
  *
- * When filling fields in a fgroup field element we don't know what kind
- * of field are we dealing with, so we should re-guess it.
+ * When filling fields inside a fgroup field element we don't know what kind
+ * of field are we dealing with, so we should re-guess it as behat_form_field
+ * does.
  *
  * @package    core_form
  * @category   test
index 04e65ff..74752b9 100644 (file)
@@ -38,4 +38,5 @@ require_once(__DIR__  . '/behat_form_select.php');
  * @copyright  2013 David Monllaó
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class behat_form_modvisible extends behat_form_select {}
+class behat_form_modvisible extends behat_form_select {
+}
index 27b5d00..8304133 100644 (file)
@@ -89,9 +89,6 @@ class behat_form_radio extends behat_form_checkbox {
      * @return bool
      */
     public function matches($expectedvalue = false) {
-        if (trim($expectedvalue) != trim($this->get_value())) {
-            return false;
-        }
-        return true;
+        return $this->text_matches($expectedvalue);
     }
 }
index 86d6b78..ac63c01 100644 (file)
@@ -204,7 +204,10 @@ class behat_form_select extends behat_form_field {
 
         // Same implementation as the parent if it is a single select.
         if (!$multiple) {
-            if (trim($expectedvalue) != trim($this->get_value())) {
+            $cleanexpectedvalue = trim($expectedvalue);
+            $selectedtext = trim($this->get_selected_options());
+            $selectedvalue = trim($this->get_selected_options(false));
+            if ($cleanexpectedvalue != $selectedvalue && $cleanexpectedvalue != $selectedtext) {
                 return false;
             }
             return true;
index 3759a17..73f8bef 100644 (file)
@@ -38,4 +38,5 @@ require_once(__DIR__  . '/behat_form_select.php');
  * @copyright  2013 David Monllaó
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class behat_form_selectyesno extends behat_form_select {}
+class behat_form_selectyesno extends behat_form_select {
+}
diff --git a/lib/behat/form_field/behat_form_text.php b/lib/behat/form_field/behat_form_text.php
new file mode 100644 (file)
index 0000000..dffdf86
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Text field class.
+ *
+ * @package    core_form
+ * @category   test
+ * @copyright  2014 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+require_once(__DIR__  . '/behat_form_field.php');
+
+/**
+ * Class for test-based fields.
+ *
+ * @package    core_form
+ * @category   test
+ * @copyright  2014 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_form_text extends behat_form_field {
+
+    /**
+     * Sets the value to a field.
+     *
+     * @param string $value
+     * @return void
+     */
+    public function set_value($value) {
+        $this->field->setValue($value);
+    }
+
+    /**
+     * Returns the current value of the element.
+     *
+     * @return string
+     */
+    public function get_value() {
+        return $this->field->getValue();
+    }
+
+    /**
+     * Matches the provided value against the current field value.
+     *
+     * @param string $expectedvalue
+     * @return bool The provided value matches the field value?
+     */
+    public function matches($expectedvalue) {
+        return $this->text_matches($expectedvalue);
+    }
+
+}
diff --git a/lib/behat/form_field/behat_form_textarea.php b/lib/behat/form_field/behat_form_textarea.php
new file mode 100644 (file)
index 0000000..c1730c2
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Textarea field class.
+ *
+ * @package    core_form
+ * @category   test
+ * @copyright  2014 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+require_once(__DIR__  . '/behat_form_text.php');
+
+/**
+ * Textarea field class.
+ *
+ * @package    core_form
+ * @category   test
+ * @copyright  2014 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_form_textarea extends behat_form_text {
+}
index 3b1f172..ffb481f 100644 (file)
@@ -36,7 +36,7 @@ Feature: Add a quiz
     And I press "Attempt quiz now"
     Then I should see "Question 1"
     And I should see "Answer the first question"
-    And I select "True" radio button
+    And I set the field "True" to "1"
     And I press "Next"
     And I should see "Answer saved"
     And I press "Submit all and finish"
index 3afcfa5..2f04e5d 100644 (file)
@@ -60,9 +60,9 @@ class behat_mod_quiz extends behat_base {
             new Given("I follow \"$quizname\""),
             new Given("I follow \"$editquiz\""),
             new Given("I press \"$addaquestion\""),
-            new Given("I select \"$questiontype\" radio button"),
+            new Given("I set the field \"$questiontype\" to \"1\""),
             new Given("I press \"$next\""),
-            new Given("I fill the moodle form with:", $table),
+            new Given("I set the following fields to these values:", $table),
             new Given("I press \"$savechanges\"")
         );
     }