Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Tests\options\Functional;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\field\Entity\FieldConfig;
|
Chris@0
|
6 use Drupal\field\Entity\FieldStorageConfig;
|
Chris@17
|
7 use Drupal\Tests\field\Functional\FieldTestBase;
|
Chris@0
|
8
|
Chris@0
|
9 /**
|
Chris@0
|
10 * Tests the Options field UI functionality.
|
Chris@0
|
11 *
|
Chris@0
|
12 * @group options
|
Chris@0
|
13 */
|
Chris@0
|
14 class OptionsFieldUITest extends FieldTestBase {
|
Chris@0
|
15
|
Chris@0
|
16 /**
|
Chris@0
|
17 * Modules to enable.
|
Chris@0
|
18 *
|
Chris@0
|
19 * @var array
|
Chris@0
|
20 */
|
Chris@0
|
21 public static $modules = ['node', 'options', 'field_test', 'taxonomy', 'field_ui'];
|
Chris@0
|
22
|
Chris@0
|
23 /**
|
Chris@0
|
24 * The name of the created content type.
|
Chris@0
|
25 *
|
Chris@0
|
26 * @var string
|
Chris@0
|
27 */
|
Chris@0
|
28 protected $typeName;
|
Chris@0
|
29
|
Chris@0
|
30 /**
|
Chris@0
|
31 * Machine name of the created content type.
|
Chris@0
|
32 *
|
Chris@0
|
33 * @var string
|
Chris@0
|
34 */
|
Chris@0
|
35 protected $type;
|
Chris@0
|
36
|
Chris@0
|
37 /**
|
Chris@0
|
38 * Name of the option field.
|
Chris@0
|
39 *
|
Chris@0
|
40 * @var string
|
Chris@0
|
41 */
|
Chris@0
|
42 protected $fieldName;
|
Chris@0
|
43
|
Chris@0
|
44 /**
|
Chris@0
|
45 * Admin path to manage field storage settings.
|
Chris@0
|
46 *
|
Chris@0
|
47 * @var string
|
Chris@0
|
48 */
|
Chris@0
|
49 protected $adminPath;
|
Chris@0
|
50
|
Chris@0
|
51 protected function setUp() {
|
Chris@0
|
52 parent::setUp();
|
Chris@0
|
53
|
Chris@0
|
54 // Create test user.
|
Chris@0
|
55 $admin_user = $this->drupalCreateUser(['access content', 'administer taxonomy', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'bypass node access', 'administer node fields', 'administer node display']);
|
Chris@0
|
56 $this->drupalLogin($admin_user);
|
Chris@0
|
57
|
Chris@0
|
58 // Create content type, with underscores.
|
Chris@0
|
59 $this->typeName = 'test_' . strtolower($this->randomMachineName());
|
Chris@0
|
60 $type = $this->drupalCreateContentType(['name' => $this->typeName, 'type' => $this->typeName]);
|
Chris@0
|
61 $this->type = $type->id();
|
Chris@0
|
62 }
|
Chris@0
|
63
|
Chris@0
|
64 /**
|
Chris@0
|
65 * Options (integer) : test 'allowed values' input.
|
Chris@0
|
66 */
|
Chris@0
|
67 public function testOptionsAllowedValuesInteger() {
|
Chris@0
|
68 $this->fieldName = 'field_options_integer';
|
Chris@0
|
69 $this->createOptionsField('list_integer');
|
Chris@0
|
70
|
Chris@0
|
71 // Flat list of textual values.
|
Chris@0
|
72 $string = "Zero\nOne";
|
Chris@0
|
73 $array = ['0' => 'Zero', '1' => 'One'];
|
Chris@0
|
74 $this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are accepted.');
|
Chris@0
|
75 // Explicit integer keys.
|
Chris@0
|
76 $string = "0|Zero\n2|Two";
|
Chris@0
|
77 $array = ['0' => 'Zero', '2' => 'Two'];
|
Chris@0
|
78 $this->assertAllowedValuesInput($string, $array, 'Integer keys are accepted.');
|
Chris@0
|
79 // Check that values can be added and removed.
|
Chris@0
|
80 $string = "0|Zero\n1|One";
|
Chris@0
|
81 $array = ['0' => 'Zero', '1' => 'One'];
|
Chris@0
|
82 $this->assertAllowedValuesInput($string, $array, 'Values can be added and removed.');
|
Chris@0
|
83 // Non-integer keys.
|
Chris@0
|
84 $this->assertAllowedValuesInput("1.1|One", 'keys must be integers', 'Non integer keys are rejected.');
|
Chris@0
|
85 $this->assertAllowedValuesInput("abc|abc", 'keys must be integers', 'Non integer keys are rejected.');
|
Chris@0
|
86 // Mixed list of keyed and unkeyed values.
|
Chris@0
|
87 $this->assertAllowedValuesInput("Zero\n1|One", 'invalid input', 'Mixed lists are rejected.');
|
Chris@0
|
88
|
Chris@0
|
89 // Create a node with actual data for the field.
|
Chris@0
|
90 $settings = [
|
Chris@0
|
91 'type' => $this->type,
|
Chris@0
|
92 $this->fieldName => [['value' => 1]],
|
Chris@0
|
93 ];
|
Chris@0
|
94 $node = $this->drupalCreateNode($settings);
|
Chris@0
|
95
|
Chris@0
|
96 // Check that a flat list of values is rejected once the field has data.
|
Chris@0
|
97 $this->assertAllowedValuesInput("Zero\nOne", 'invalid input', 'Unkeyed lists are rejected once the field has data.');
|
Chris@0
|
98
|
Chris@0
|
99 // Check that values can be added but values in use cannot be removed.
|
Chris@0
|
100 $string = "0|Zero\n1|One\n2|Two";
|
Chris@0
|
101 $array = ['0' => 'Zero', '1' => 'One', '2' => 'Two'];
|
Chris@0
|
102 $this->assertAllowedValuesInput($string, $array, 'Values can be added.');
|
Chris@0
|
103 $string = "0|Zero\n1|One";
|
Chris@0
|
104 $array = ['0' => 'Zero', '1' => 'One'];
|
Chris@0
|
105 $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
Chris@0
|
106 $this->assertAllowedValuesInput("0|Zero", 'some values are being removed while currently in use', 'Values in use cannot be removed.');
|
Chris@0
|
107
|
Chris@0
|
108 // Delete the node, remove the value.
|
Chris@0
|
109 $node->delete();
|
Chris@0
|
110 $string = "0|Zero";
|
Chris@0
|
111 $array = ['0' => 'Zero'];
|
Chris@0
|
112 $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
Chris@0
|
113
|
Chris@0
|
114 // Check that the same key can only be used once.
|
Chris@0
|
115 $string = "0|Zero\n0|One";
|
Chris@0
|
116 $array = ['0' => 'One'];
|
Chris@0
|
117 $this->assertAllowedValuesInput($string, $array, 'Same value cannot be used multiple times.');
|
Chris@0
|
118 }
|
Chris@0
|
119
|
Chris@0
|
120 /**
|
Chris@0
|
121 * Options (float) : test 'allowed values' input.
|
Chris@0
|
122 */
|
Chris@0
|
123 public function testOptionsAllowedValuesFloat() {
|
Chris@0
|
124 $this->fieldName = 'field_options_float';
|
Chris@0
|
125 $this->createOptionsField('list_float');
|
Chris@0
|
126
|
Chris@0
|
127 // Flat list of textual values.
|
Chris@0
|
128 $string = "Zero\nOne";
|
Chris@0
|
129 $array = ['0' => 'Zero', '1' => 'One'];
|
Chris@0
|
130 $this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are accepted.');
|
Chris@0
|
131 // Explicit numeric keys.
|
Chris@0
|
132 $string = "0|Zero\n.5|Point five";
|
Chris@0
|
133 $array = ['0' => 'Zero', '0.5' => 'Point five'];
|
Chris@0
|
134 $this->assertAllowedValuesInput($string, $array, 'Integer keys are accepted.');
|
Chris@0
|
135 // Check that values can be added and removed.
|
Chris@0
|
136 $string = "0|Zero\n.5|Point five\n1.0|One";
|
Chris@0
|
137 $array = ['0' => 'Zero', '0.5' => 'Point five', '1' => 'One'];
|
Chris@0
|
138 $this->assertAllowedValuesInput($string, $array, 'Values can be added and removed.');
|
Chris@0
|
139 // Non-numeric keys.
|
Chris@0
|
140 $this->assertAllowedValuesInput("abc|abc\n", 'each key must be a valid integer or decimal', 'Non numeric keys are rejected.');
|
Chris@0
|
141 // Mixed list of keyed and unkeyed values.
|
Chris@0
|
142 $this->assertAllowedValuesInput("Zero\n1|One\n", 'invalid input', 'Mixed lists are rejected.');
|
Chris@0
|
143
|
Chris@0
|
144 // Create a node with actual data for the field.
|
Chris@0
|
145 $settings = [
|
Chris@0
|
146 'type' => $this->type,
|
Chris@0
|
147 $this->fieldName => [['value' => .5]],
|
Chris@0
|
148 ];
|
Chris@0
|
149 $node = $this->drupalCreateNode($settings);
|
Chris@0
|
150
|
Chris@0
|
151 // Check that a flat list of values is rejected once the field has data.
|
Chris@0
|
152 $this->assertAllowedValuesInput("Zero\nOne", 'invalid input', 'Unkeyed lists are rejected once the field has data.');
|
Chris@0
|
153
|
Chris@0
|
154 // Check that values can be added but values in use cannot be removed.
|
Chris@0
|
155 $string = "0|Zero\n.5|Point five\n2|Two";
|
Chris@0
|
156 $array = ['0' => 'Zero', '0.5' => 'Point five', '2' => 'Two'];
|
Chris@0
|
157 $this->assertAllowedValuesInput($string, $array, 'Values can be added.');
|
Chris@0
|
158 $string = "0|Zero\n.5|Point five";
|
Chris@0
|
159 $array = ['0' => 'Zero', '0.5' => 'Point five'];
|
Chris@0
|
160 $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
Chris@0
|
161 $this->assertAllowedValuesInput("0|Zero", 'some values are being removed while currently in use', 'Values in use cannot be removed.');
|
Chris@0
|
162
|
Chris@0
|
163 // Delete the node, remove the value.
|
Chris@0
|
164 $node->delete();
|
Chris@0
|
165 $string = "0|Zero";
|
Chris@0
|
166 $array = ['0' => 'Zero'];
|
Chris@0
|
167 $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
Chris@0
|
168
|
Chris@0
|
169 // Check that the same key can only be used once.
|
Chris@0
|
170 $string = "0.5|Point five\n0.5|Half";
|
Chris@0
|
171 $array = ['0.5' => 'Half'];
|
Chris@0
|
172 $this->assertAllowedValuesInput($string, $array, 'Same value cannot be used multiple times.');
|
Chris@0
|
173
|
Chris@0
|
174 // Check that different forms of the same float value cannot be used.
|
Chris@0
|
175 $string = "0|Zero\n.5|Point five\n0.5|Half";
|
Chris@0
|
176 $array = ['0' => 'Zero', '0.5' => 'Half'];
|
Chris@0
|
177 $this->assertAllowedValuesInput($string, $array, 'Different forms of the same value cannot be used.');
|
Chris@0
|
178 }
|
Chris@0
|
179
|
Chris@0
|
180 /**
|
Chris@0
|
181 * Options (text) : test 'allowed values' input.
|
Chris@0
|
182 */
|
Chris@0
|
183 public function testOptionsAllowedValuesText() {
|
Chris@0
|
184 $this->fieldName = 'field_options_text';
|
Chris@0
|
185 $this->createOptionsField('list_string');
|
Chris@0
|
186
|
Chris@0
|
187 // Flat list of textual values.
|
Chris@0
|
188 $string = "Zero\nOne";
|
Chris@0
|
189 $array = ['Zero' => 'Zero', 'One' => 'One'];
|
Chris@0
|
190 $this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are accepted.');
|
Chris@0
|
191 // Explicit keys.
|
Chris@0
|
192 $string = "zero|Zero\none|One";
|
Chris@0
|
193 $array = ['zero' => 'Zero', 'one' => 'One'];
|
Chris@0
|
194 $this->assertAllowedValuesInput($string, $array, 'Explicit keys are accepted.');
|
Chris@0
|
195 // Check that values can be added and removed.
|
Chris@0
|
196 $string = "zero|Zero\ntwo|Two";
|
Chris@0
|
197 $array = ['zero' => 'Zero', 'two' => 'Two'];
|
Chris@0
|
198 $this->assertAllowedValuesInput($string, $array, 'Values can be added and removed.');
|
Chris@0
|
199 // Mixed list of keyed and unkeyed values.
|
Chris@0
|
200 $string = "zero|Zero\nOne\n";
|
Chris@0
|
201 $array = ['zero' => 'Zero', 'One' => 'One'];
|
Chris@0
|
202 $this->assertAllowedValuesInput($string, $array, 'Mixed lists are accepted.');
|
Chris@0
|
203 // Overly long keys.
|
Chris@0
|
204 $this->assertAllowedValuesInput("zero|Zero\n" . $this->randomMachineName(256) . "|One", 'each key must be a string at most 255 characters long', 'Overly long keys are rejected.');
|
Chris@0
|
205
|
Chris@0
|
206 // Create a node with actual data for the field.
|
Chris@0
|
207 $settings = [
|
Chris@0
|
208 'type' => $this->type,
|
Chris@0
|
209 $this->fieldName => [['value' => 'One']],
|
Chris@0
|
210 ];
|
Chris@0
|
211 $node = $this->drupalCreateNode($settings);
|
Chris@0
|
212
|
Chris@0
|
213 // Check that flat lists of values are still accepted once the field has
|
Chris@0
|
214 // data.
|
Chris@0
|
215 $string = "Zero\nOne";
|
Chris@0
|
216 $array = ['Zero' => 'Zero', 'One' => 'One'];
|
Chris@0
|
217 $this->assertAllowedValuesInput($string, $array, 'Unkeyed lists are still accepted once the field has data.');
|
Chris@0
|
218
|
Chris@0
|
219 // Check that values can be added but values in use cannot be removed.
|
Chris@0
|
220 $string = "Zero\nOne\nTwo";
|
Chris@0
|
221 $array = ['Zero' => 'Zero', 'One' => 'One', 'Two' => 'Two'];
|
Chris@0
|
222 $this->assertAllowedValuesInput($string, $array, 'Values can be added.');
|
Chris@0
|
223 $string = "Zero\nOne";
|
Chris@0
|
224 $array = ['Zero' => 'Zero', 'One' => 'One'];
|
Chris@0
|
225 $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
Chris@0
|
226 $this->assertAllowedValuesInput("Zero", 'some values are being removed while currently in use', 'Values in use cannot be removed.');
|
Chris@0
|
227
|
Chris@0
|
228 // Delete the node, remove the value.
|
Chris@0
|
229 $node->delete();
|
Chris@0
|
230 $string = "Zero";
|
Chris@0
|
231 $array = ['Zero' => 'Zero'];
|
Chris@0
|
232 $this->assertAllowedValuesInput($string, $array, 'Values not in use can be removed.');
|
Chris@0
|
233
|
Chris@0
|
234 // Check that string values with dots can be used.
|
Chris@0
|
235 $string = "Zero\nexample.com|Example";
|
Chris@0
|
236 $array = ['Zero' => 'Zero', 'example.com' => 'Example'];
|
Chris@0
|
237 $this->assertAllowedValuesInput($string, $array, 'String value with dot is supported.');
|
Chris@0
|
238
|
Chris@0
|
239 // Check that the same key can only be used once.
|
Chris@0
|
240 $string = "zero|Zero\nzero|One";
|
Chris@0
|
241 $array = ['zero' => 'One'];
|
Chris@0
|
242 $this->assertAllowedValuesInput($string, $array, 'Same value cannot be used multiple times.');
|
Chris@0
|
243 }
|
Chris@0
|
244
|
Chris@0
|
245 /**
|
Chris@0
|
246 * Options (text) : test 'trimmed values' input.
|
Chris@0
|
247 */
|
Chris@0
|
248 public function testOptionsTrimmedValuesText() {
|
Chris@0
|
249 $this->fieldName = 'field_options_trimmed_text';
|
Chris@0
|
250 $this->createOptionsField('list_string');
|
Chris@0
|
251
|
Chris@0
|
252 // Explicit keys.
|
Chris@0
|
253 $string = "zero |Zero\none | One";
|
Chris@0
|
254 $array = ['zero' => 'Zero', 'one' => 'One'];
|
Chris@0
|
255 $this->assertAllowedValuesInput($string, $array, 'Explicit keys are accepted and trimmed.');
|
Chris@0
|
256 }
|
Chris@0
|
257
|
Chris@0
|
258 /**
|
Chris@0
|
259 * Helper function to create list field of a given type.
|
Chris@0
|
260 *
|
Chris@0
|
261 * @param string $type
|
Chris@0
|
262 * One of 'list_integer', 'list_float' or 'list_string'.
|
Chris@0
|
263 */
|
Chris@0
|
264 protected function createOptionsField($type) {
|
Chris@0
|
265 // Create a field.
|
Chris@0
|
266 FieldStorageConfig::create([
|
Chris@0
|
267 'field_name' => $this->fieldName,
|
Chris@0
|
268 'entity_type' => 'node',
|
Chris@0
|
269 'type' => $type,
|
Chris@0
|
270 ])->save();
|
Chris@0
|
271 FieldConfig::create([
|
Chris@0
|
272 'field_name' => $this->fieldName,
|
Chris@0
|
273 'entity_type' => 'node',
|
Chris@0
|
274 'bundle' => $this->type,
|
Chris@0
|
275 ])->save();
|
Chris@0
|
276
|
Chris@0
|
277 entity_get_form_display('node', $this->type, 'default')->setComponent($this->fieldName)->save();
|
Chris@0
|
278
|
Chris@0
|
279 $this->adminPath = 'admin/structure/types/manage/' . $this->type . '/fields/node.' . $this->type . '.' . $this->fieldName . '/storage';
|
Chris@0
|
280 }
|
Chris@0
|
281
|
Chris@0
|
282 /**
|
Chris@0
|
283 * Tests a string input for the 'allowed values' form element.
|
Chris@0
|
284 *
|
Chris@0
|
285 * @param $input_string
|
Chris@0
|
286 * The input string, in the pipe-linefeed format expected by the form
|
Chris@0
|
287 * element.
|
Chris@0
|
288 * @param $result
|
Chris@0
|
289 * Either an expected resulting array in
|
Chris@0
|
290 * $field->getSetting('allowed_values'), or an expected error message.
|
Chris@0
|
291 * @param $message
|
Chris@0
|
292 * Message to display.
|
Chris@0
|
293 */
|
Chris@0
|
294 public function assertAllowedValuesInput($input_string, $result, $message) {
|
Chris@0
|
295 $edit = ['settings[allowed_values]' => $input_string];
|
Chris@0
|
296 $this->drupalPostForm($this->adminPath, $edit, t('Save field settings'));
|
Chris@0
|
297 $this->assertNoRaw('&lt;', 'The page does not have double escaped HTML tags.');
|
Chris@0
|
298
|
Chris@0
|
299 if (is_string($result)) {
|
Chris@0
|
300 $this->assertText($result, $message);
|
Chris@0
|
301 }
|
Chris@0
|
302 else {
|
Chris@0
|
303 $field_storage = FieldStorageConfig::loadByName('node', $this->fieldName);
|
Chris@0
|
304 $this->assertIdentical($field_storage->getSetting('allowed_values'), $result, $message);
|
Chris@0
|
305 }
|
Chris@0
|
306 }
|
Chris@0
|
307
|
Chris@0
|
308 /**
|
Chris@0
|
309 * Tests normal and key formatter display on node display.
|
Chris@0
|
310 */
|
Chris@0
|
311 public function testNodeDisplay() {
|
Chris@0
|
312 $this->fieldName = strtolower($this->randomMachineName());
|
Chris@0
|
313 $this->createOptionsField('list_integer');
|
Chris@0
|
314 $node = $this->drupalCreateNode(['type' => $this->type]);
|
Chris@0
|
315
|
Chris@0
|
316 $on = $this->randomMachineName();
|
Chris@0
|
317 $off = $this->randomMachineName();
|
Chris@0
|
318 $edit = [
|
Chris@0
|
319 'settings[allowed_values]' =>
|
Chris@0
|
320 "1|$on
|
Chris@0
|
321 0|$off",
|
Chris@0
|
322 ];
|
Chris@0
|
323
|
Chris@0
|
324 $this->drupalPostForm($this->adminPath, $edit, t('Save field settings'));
|
Chris@0
|
325 $this->assertText(format_string('Updated field @field_name field settings.', ['@field_name' => $this->fieldName]), "The 'On' and 'Off' form fields work for boolean fields.");
|
Chris@0
|
326
|
Chris@0
|
327 // Select a default value.
|
Chris@0
|
328 $edit = [
|
Chris@0
|
329 $this->fieldName => '1',
|
Chris@0
|
330 ];
|
Chris@0
|
331 $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
|
Chris@0
|
332
|
Chris@0
|
333 // Check the node page and see if the values are correct.
|
Chris@0
|
334 $file_formatters = ['list_default', 'list_key'];
|
Chris@0
|
335 foreach ($file_formatters as $formatter) {
|
Chris@0
|
336 $edit = [
|
Chris@0
|
337 "fields[$this->fieldName][type]" => $formatter,
|
Chris@0
|
338 "fields[$this->fieldName][region]" => 'content',
|
Chris@0
|
339 ];
|
Chris@0
|
340 $this->drupalPostForm('admin/structure/types/manage/' . $this->typeName . '/display', $edit, t('Save'));
|
Chris@0
|
341 $this->drupalGet('node/' . $node->id());
|
Chris@0
|
342
|
Chris@0
|
343 if ($formatter == 'list_default') {
|
Chris@0
|
344 $output = $on;
|
Chris@0
|
345 }
|
Chris@0
|
346 else {
|
Chris@0
|
347 $output = '1';
|
Chris@0
|
348 }
|
Chris@0
|
349
|
Chris@0
|
350 $elements = $this->xpath('//div[text()="' . $output . '"]');
|
Chris@0
|
351 $this->assertEqual(count($elements), 1, 'Correct options found.');
|
Chris@0
|
352 }
|
Chris@0
|
353 }
|
Chris@0
|
354
|
Chris@0
|
355 }
|