3 namespace Drupal\field\Tests\Number;
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\field\Entity\FieldConfig;
7 use Drupal\node\Entity\Node;
8 use Drupal\simpletest\WebTestBase;
9 use Drupal\field\Entity\FieldStorageConfig;
12 * Tests the creation of numeric fields.
16 class NumberFieldTest extends WebTestBase {
23 public static $modules = ['node', 'entity_test', 'field_ui'];
25 protected function setUp() {
27 $this->drupalLogin($this->drupalCreateUser([
29 'administer entity_test content',
30 'administer content types',
31 'administer node fields',
32 'administer node display',
34 'administer entity_test fields',
41 public function testNumberDecimalField() {
42 // Create a field with settings to validate.
43 $field_name = Unicode::strtolower($this->randomMachineName());
44 FieldStorageConfig::create([
45 'field_name' => $field_name,
46 'entity_type' => 'entity_test',
48 'settings' => ['precision' => 8, 'scale' => 4],
51 'field_name' => $field_name,
52 'entity_type' => 'entity_test',
53 'bundle' => 'entity_test',
56 entity_get_form_display('entity_test', 'entity_test', 'default')
57 ->setComponent($field_name, [
60 'placeholder' => '0.00'
64 entity_get_display('entity_test', 'entity_test', 'default')
65 ->setComponent($field_name, [
66 'type' => 'number_decimal',
70 // Display creation form.
71 $this->drupalGet('entity_test/add');
72 $this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
73 $this->assertRaw('placeholder="0.00"');
75 // Submit a signed decimal value within the allowed precision and scale.
76 $value = '-1234.5678';
78 "{$field_name}[0][value]" => $value,
80 $this->drupalPostForm(NULL, $edit, t('Save'));
81 preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
83 $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
84 $this->assertRaw($value, 'Value is displayed.');
86 // Try to create entries with more than one decimal separator; assert fail.
95 foreach ($wrong_entries as $wrong_entry) {
96 $this->drupalGet('entity_test/add');
98 "{$field_name}[0][value]" => $wrong_entry,
100 $this->drupalPostForm(NULL, $edit, t('Save'));
101 $this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save decimal value with more than one decimal point.');
104 // Try to create entries with minus sign not in the first position.
113 foreach ($wrong_entries as $wrong_entry) {
114 $this->drupalGet('entity_test/add');
116 "{$field_name}[0][value]" => $wrong_entry,
118 $this->drupalPostForm(NULL, $edit, t('Save'));
119 $this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save decimal value with minus sign in the wrong position.');
124 * Test integer field.
126 public function testNumberIntegerField() {
127 $minimum = rand(-4000, -2000);
128 $maximum = rand(2000, 4000);
130 // Create a field with settings to validate.
131 $field_name = Unicode::strtolower($this->randomMachineName());
132 $storage = FieldStorageConfig::create([
133 'field_name' => $field_name,
134 'entity_type' => 'entity_test',
139 FieldConfig::create([
140 'field_name' => $field_name,
141 'entity_type' => 'entity_test',
142 'bundle' => 'entity_test',
146 'prefix' => 'ThePrefix',
150 entity_get_form_display('entity_test', 'entity_test', 'default')
151 ->setComponent($field_name, [
158 entity_get_display('entity_test', 'entity_test', 'default')
159 ->setComponent($field_name, [
160 'type' => 'number_integer',
162 'prefix_suffix' => FALSE,
167 // Check the storage schema.
180 $this->assertEqual($storage->getSchema(), $expected);
182 // Display creation form.
183 $this->drupalGet('entity_test/add');
184 $this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
185 $this->assertRaw('placeholder="4"');
187 // Submit a valid integer
188 $value = rand($minimum, $maximum);
190 "{$field_name}[0][value]" => $value,
192 $this->drupalPostForm(NULL, $edit, t('Save'));
193 preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
195 $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
197 // Try to set a value below the minimum value
198 $this->drupalGet('entity_test/add');
200 "{$field_name}[0][value]" => $minimum - 1,
202 $this->drupalPostForm(NULL, $edit, t('Save'));
203 $this->assertRaw(t('%name must be higher than or equal to %minimum.', ['%name' => $field_name, '%minimum' => $minimum]), 'Correctly failed to save integer value less than minimum allowed value.');
205 // Try to set a decimal value
206 $this->drupalGet('entity_test/add');
208 "{$field_name}[0][value]" => 1.5,
210 $this->drupalPostForm(NULL, $edit, t('Save'));
211 $this->assertRaw(t('%name is not a valid number.', ['%name' => $field_name]), 'Correctly failed to save decimal value to integer field.');
213 // Try to set a value above the maximum value
214 $this->drupalGet('entity_test/add');
216 "{$field_name}[0][value]" => $maximum + 1,
218 $this->drupalPostForm(NULL, $edit, t('Save'));
219 $this->assertRaw(t('%name must be lower than or equal to %maximum.', ['%name' => $field_name, '%maximum' => $maximum]), 'Correctly failed to save integer value greater than maximum allowed value.');
221 // Try to set a wrong integer value.
222 $this->drupalGet('entity_test/add');
224 "{$field_name}[0][value]" => '20-40',
226 $this->drupalPostForm(NULL, $edit, t('Save'));
227 $this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save wrong integer value.');
229 // Test with valid entries.
236 foreach ($valid_entries as $valid_entry) {
237 $this->drupalGet('entity_test/add');
239 "{$field_name}[0][value]" => $valid_entry,
241 $this->drupalPostForm(NULL, $edit, t('Save'));
242 preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
244 $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
245 $this->assertRaw($valid_entry, 'Value is displayed.');
246 $this->assertNoFieldByXpath('//div[@content="' . $valid_entry . '"]', NULL, 'The "content" attribute is not present since the Prefix is not being displayed');
249 // Test for the content attribute when a Prefix is displayed. Presumably this also tests for the attribute when a Suffix is displayed.
250 entity_get_display('entity_test', 'entity_test', 'default')
251 ->setComponent($field_name, [
252 'type' => 'number_integer',
254 'prefix_suffix' => TRUE,
258 $integer_value = '123';
259 $this->drupalGet('entity_test/add');
261 "{$field_name}[0][value]" => $integer_value,
263 $this->drupalPostForm(NULL, $edit, t('Save'));
264 preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
266 $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
267 $this->drupalGet('entity_test/' . $id);
268 $this->assertFieldByXPath('//div[@content="' . $integer_value . '"]', 'ThePrefix' . $integer_value, 'The "content" attribute has been set to the value of the field, and the prefix is being displayed.');
274 public function testNumberFloatField() {
275 // Create a field with settings to validate.
276 $field_name = Unicode::strtolower($this->randomMachineName());
277 FieldStorageConfig::create([
278 'field_name' => $field_name,
279 'entity_type' => 'entity_test',
283 FieldConfig::create([
284 'field_name' => $field_name,
285 'entity_type' => 'entity_test',
286 'bundle' => 'entity_test',
289 entity_get_form_display('entity_test', 'entity_test', 'default')
290 ->setComponent($field_name, [
293 'placeholder' => '0.00'
298 entity_get_display('entity_test', 'entity_test', 'default')
299 ->setComponent($field_name, [
300 'type' => 'number_decimal',
304 // Display creation form.
305 $this->drupalGet('entity_test/add');
306 $this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed');
307 $this->assertRaw('placeholder="0.00"');
309 // Submit a signed decimal value within the allowed precision and scale.
310 $value = '-1234.5678';
312 "{$field_name}[0][value]" => $value,
314 $this->drupalPostForm(NULL, $edit, t('Save'));
315 preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
317 $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created');
319 // Ensure that the 'number_decimal' formatter displays the number with the
320 // expected rounding.
321 $this->drupalGet('entity_test/' . $id);
322 $this->assertRaw(round($value, 2));
324 // Try to create entries with more than one decimal separator; assert fail.
333 foreach ($wrong_entries as $wrong_entry) {
334 $this->drupalGet('entity_test/add');
336 "{$field_name}[0][value]" => $wrong_entry,
338 $this->drupalPostForm(NULL, $edit, t('Save'));
339 $this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save float value with more than one decimal point.');
342 // Try to create entries with minus sign not in the first position.
351 foreach ($wrong_entries as $wrong_entry) {
352 $this->drupalGet('entity_test/add');
354 "{$field_name}[0][value]" => $wrong_entry,
356 $this->drupalPostForm(NULL, $edit, t('Save'));
357 $this->assertRaw(t('%name must be a number.', ['%name' => $field_name]), 'Correctly failed to save float value with minus sign in the wrong position.');
362 * Test default formatter behavior
364 public function testNumberFormatter() {
365 $type = Unicode::strtolower($this->randomMachineName());
366 $float_field = Unicode::strtolower($this->randomMachineName());
367 $integer_field = Unicode::strtolower($this->randomMachineName());
368 $thousand_separators = ['', '.', ',', ' ', chr(8201), "'"];
369 $decimal_separators = ['.', ','];
370 $prefix = $this->randomMachineName();
371 $suffix = $this->randomMachineName();
372 $random_float = rand(0, pow(10, 6));
373 $random_integer = rand(0, pow(10, 6));
375 // Create a content type containing float and integer fields.
376 $this->drupalCreateContentType(['type' => $type]);
378 FieldStorageConfig::create([
379 'field_name' => $float_field,
380 'entity_type' => 'node',
384 FieldStorageConfig::create([
385 'field_name' => $integer_field,
386 'entity_type' => 'node',
390 FieldConfig::create([
391 'field_name' => $float_field,
392 'entity_type' => 'node',
400 FieldConfig::create([
401 'field_name' => $integer_field,
402 'entity_type' => 'node',
410 entity_get_form_display('node', $type, 'default')
411 ->setComponent($float_field, [
414 'placeholder' => '0.00'
417 ->setComponent($integer_field, [
420 'placeholder' => '0.00'
425 entity_get_display('node', $type, 'default')
426 ->setComponent($float_field, [
427 'type' => 'number_decimal',
429 ->setComponent($integer_field, [
430 'type' => 'number_unformatted',
434 // Create a node to test formatters.
435 $node = Node::create([
437 'title' => $this->randomMachineName(),
438 $float_field => ['value' => $random_float],
439 $integer_field => ['value' => $random_integer],
443 // Go to manage display page.
444 $this->drupalGet("admin/structure/types/manage/$type/display");
446 // Configure number_decimal formatter for the 'float' field type.
447 $thousand_separator = $thousand_separators[array_rand($thousand_separators)];
448 $decimal_separator = $decimal_separators[array_rand($decimal_separators)];
449 $scale = rand(0, 10);
451 $this->drupalPostAjaxForm(NULL, [], "${float_field}_settings_edit");
453 "fields[${float_field}][settings_edit_form][settings][prefix_suffix]" => TRUE,
454 "fields[${float_field}][settings_edit_form][settings][scale]" => $scale,
455 "fields[${float_field}][settings_edit_form][settings][decimal_separator]" => $decimal_separator,
456 "fields[${float_field}][settings_edit_form][settings][thousand_separator]" => $thousand_separator,
458 $this->drupalPostAjaxForm(NULL, $edit, "${float_field}_plugin_settings_update");
459 $this->drupalPostForm(NULL, [], t('Save'));
461 // Check number_decimal and number_unformatted formatters behavior.
462 $this->drupalGet('node/' . $node->id());
463 $float_formatted = number_format($random_float, $scale, $decimal_separator, $thousand_separator);
464 $this->assertRaw("$prefix$float_formatted$suffix", 'Prefix and suffix added');
465 $this->assertRaw((string) $random_integer);
467 // Configure the number_decimal formatter.
468 entity_get_display('node', $type, 'default')
469 ->setComponent($integer_field, [
470 'type' => 'number_integer',
473 $this->drupalGet("admin/structure/types/manage/$type/display");
475 $thousand_separator = $thousand_separators[array_rand($thousand_separators)];
477 $this->drupalPostAjaxForm(NULL, [], "${integer_field}_settings_edit");
479 "fields[${integer_field}][settings_edit_form][settings][prefix_suffix]" => FALSE,
480 "fields[${integer_field}][settings_edit_form][settings][thousand_separator]" => $thousand_separator,
482 $this->drupalPostAjaxForm(NULL, $edit, "${integer_field}_plugin_settings_update");
483 $this->drupalPostForm(NULL, [], t('Save'));
485 // Check number_integer formatter behavior.
486 $this->drupalGet('node/' . $node->id());
488 $integer_formatted = number_format($random_integer, 0, '', $thousand_separator);
489 $this->assertRaw($integer_formatted, 'Random integer formatted');
493 * Tests setting the minimum value of a float field through the interface.
495 public function testCreateNumberFloatField() {
496 // Create a float field.
497 $field_name = Unicode::strtolower($this->randomMachineName());
498 FieldStorageConfig::create([
499 'field_name' => $field_name,
500 'entity_type' => 'entity_test',
504 $field = FieldConfig::create([
505 'field_name' => $field_name,
506 'entity_type' => 'entity_test',
507 'bundle' => 'entity_test',
511 // Set the minimum value to a float value.
512 $this->assertSetMinimumValue($field, 0.0001);
513 // Set the minimum value to an integer value.
514 $this->assertSetMinimumValue($field, 1);
518 * Tests setting the minimum value of a decimal field through the interface.
520 public function testCreateNumberDecimalField() {
521 // Create a decimal field.
522 $field_name = Unicode::strtolower($this->randomMachineName());
523 FieldStorageConfig::create([
524 'field_name' => $field_name,
525 'entity_type' => 'entity_test',
529 $field = FieldConfig::create([
530 'field_name' => $field_name,
531 'entity_type' => 'entity_test',
532 'bundle' => 'entity_test',
536 // Set the minimum value to a decimal value.
537 $this->assertSetMinimumValue($field, 0.1);
538 // Set the minimum value to an integer value.
539 $this->assertSetMinimumValue($field, 1);
543 * Helper function to set the minimum value of a field.
545 public function assertSetMinimumValue($field, $minimum_value) {
546 $field_configuration_url = 'entity_test/structure/entity_test/fields/entity_test.entity_test.' . $field->getName();
548 // Set the minimum value.
550 'settings[min]' => $minimum_value,
552 $this->drupalPostForm($field_configuration_url, $edit, t('Save settings'));
553 // Check if an error message is shown.
554 $this->assertNoRaw(t('%name is not a valid number.', ['%name' => t('Minimum')]), 'Saved ' . gettype($minimum_value) . ' value as minimal value on a ' . $field->getType() . ' field');
555 // Check if a success message is shown.
556 $this->assertRaw(t('Saved %label configuration.', ['%label' => $field->getLabel()]));
557 // Check if the minimum value was actually set.
558 $this->drupalGet($field_configuration_url);
559 $this->assertFieldById('edit-settings-min', $minimum_value, 'Minimal ' . gettype($minimum_value) . ' value was set on a ' . $field->getType() . ' field.');