weekly release 4.1dev
[moodle.git] / lib / behat / form_field / behat_form_select.php
CommitLineData
23ebc481
DM
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Single select form field class.
19 *
20 * @package core_form
21 * @category test
22 * @copyright 2012 David MonllaĆ³
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
27
28require_once(__DIR__ . '/behat_form_field.php');
29
30/**
31 * Single select form field.
32 *
33 * @package core_form
34 * @category test
35 * @copyright 2012 David MonllaĆ³
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 */
38class behat_form_select extends behat_form_field {
39
40 /**
5f66d46e 41 * Sets the value(s) of a select element.
23ebc481 42 *
d1e55a47
DM
43 * Seems an easy select, but there are lots of combinations
44 * of browsers and operative systems and each one manages the
5f66d46e 45 * autosubmits and the multiple option selects in a different way.
d1e55a47 46 *
5f66d46e 47 * @param string $value plain value or comma separated values if multiple. Commas in values escaped with backslash.
23ebc481
DM
48 * @return void
49 */
50 public function set_value($value) {
28abad1a 51
5f66d46e
EL
52 // Is the select multiple?
53 $multiple = $this->field->hasAttribute('multiple');
5f66d46e
EL
54
55 // Here we select the option(s).
56 if ($multiple) {
57 // Split and decode values. Comma separated list of values allowed. With valuable commas escaped with backslash.
42ad096f 58 $options = preg_replace('/\\\,/', ',', preg_split('/(?<!\\\),/', trim($value)));
5f66d46e
EL
59 // This is a multiple select, let's pass the multiple flag after first option.
60 $afterfirstoption = false;
61 foreach ($options as $option) {
62 $this->field->selectOption(trim($option), $afterfirstoption);
63 $afterfirstoption = true;
64 }
65 } else {
d5f211d0 66 // By default, assume the passed value is a non-multiple option.
42ad096f
RT
67 $this->field->selectOption(trim($value));
68 }
23ebc481
DM
69 }
70
71 /**
5f66d46e 72 * Returns the text of the currently selected options.
23ebc481 73 *
5f66d46e 74 * @return string Comma separated if multiple options are selected. Commas in option texts escaped with backslash.
23ebc481
DM
75 */
76 public function get_value() {
c3f1e953
DM
77 return $this->get_selected_options();
78 }
79
80 /**
81 * Returns whether the provided argument matches the current value.
82 *
83 * @param mixed $expectedvalue
84 * @return bool
85 */
86 public function matches($expectedvalue) {
87
88 $multiple = $this->field->hasAttribute('multiple');
89
90 // Same implementation as the parent if it is a single select.
91 if (!$multiple) {
8aff0eec
DM
92 $cleanexpectedvalue = trim($expectedvalue);
93 $selectedtext = trim($this->get_selected_options());
94 $selectedvalue = trim($this->get_selected_options(false));
95 if ($cleanexpectedvalue != $selectedvalue && $cleanexpectedvalue != $selectedtext) {
c3f1e953
DM
96 return false;
97 }
98 return true;
99 }
100
101 // We are dealing with a multi-select.
102
c3f1e953
DM
103 // Unescape + trim all options and flip it to have the expected values as keys.
104 $expectedoptions = $this->get_unescaped_options($expectedvalue);
105
106 // Get currently selected option's texts.
107 $texts = $this->get_selected_options(true);
108 $selectedoptiontexts = $this->get_unescaped_options($texts);
109
110 // Get currently selected option's values.
111 $values = $this->get_selected_options(false);
112 $selectedoptionvalues = $this->get_unescaped_options($values);
113
c3f1e953 114 // We check against string-ordered lists of options.
2abb1e88
MG
115 if ($expectedoptions !== $selectedoptiontexts &&
116 $expectedoptions !== $selectedoptionvalues) {
c3f1e953
DM
117 return false;
118 }
119
120 return true;
121 }
122
123 /**
124 * Cleans the list of options and returns it as a string separating options with |||.
125 *
126 * @param string $value The string containing the escaped options.
127 * @return string The options
128 */
129 protected function get_unescaped_options($value) {
130
131 // Can be multiple comma separated, with valuable commas escaped with backslash.
132 $optionsarray = array_map(
133 'trim',
134 preg_replace('/\\\,/', ',',
135 preg_split('/(?<!\\\),/', $value)
136 )
137 );
138
139 // Sort by value (keeping the keys is irrelevant).
140 core_collator::asort($optionsarray, SORT_STRING);
141
142 // Returning it as a string which is easier to match against other values.
143 return implode('|||', $optionsarray);
144 }
145
146 /**
147 * Returns the field selected values.
148 *
149 * Externalized from the common behat_form_field API method get_value() as
150 * matches() needs to check against both values and texts.
151 *
152 * @param bool $returntexts Returns the options texts or the options values.
153 * @return string
154 */
155 protected function get_selected_options($returntexts = true) {
156
955118d8 157 $method = 'getHtml';
c3f1e953
DM
158 if ($returntexts === false) {
159 $method = 'getValue';
160 }
5f66d46e
EL
161
162 // Is the select multiple?
163 $multiple = $this->field->hasAttribute('multiple');
164
165 $selectedoptions = array(); // To accumulate found selected options.
166
42ad096f
RT
167 // Driver returns the values as an array or as a string depending
168 // on whether multiple options are selected or not.
169 $values = $this->field->getValue();
170 if (!is_array($values)) {
171 $values = array($values);
172 }
c3f1e953 173
42ad096f
RT
174 // Get all the options in the select and extract their value/text pairs.
175 $alloptions = $this->field->findAll('xpath', '//option');
176 foreach ($alloptions as $option) {
177 // Is it selected?
178 if (in_array($option->getValue(), $values)) {
179 if ($multiple) {
180 // If the select is multiple, text commas must be encoded.
181 $selectedoptions[] = trim(str_replace(',', '\,', $option->{$method}()));
182 } else {
183 $selectedoptions[] = trim($option->{$method}());
5f66d46e
EL
184 }
185 }
186 }
187
188 return implode(', ', $selectedoptions);
23ebc481 189 }
c3f1e953
DM
190
191 /**
192 * Returns the opton XPath based on it's select xpath.
193 *
194 * @param string $option
195 * @param string $selectxpath
196 * @return string xpath
197 */
198 protected function get_option_xpath($option, $selectxpath) {
921faad9 199 $valueliteral = behat_context_helper::escape(trim($option));
c3f1e953
DM
200 return $selectxpath . "/descendant::option[(./@value=$valueliteral or normalize-space(.)=$valueliteral)]";
201 }
23ebc481 202}