DateTimeFieldTest.php 20.7 KB
Newer Older
1 2 3 4
<?php

/**
 * @file
5
 * Contains \Drupal\datetime\Tests\DateTimeFieldTest.
6 7 8 9
 */

namespace Drupal\datetime\Tests;

10
use Drupal\Component\Utility\Unicode;
11
use Drupal\Core\Entity\Entity\EntityViewDisplay;
12 13 14 15 16
use Drupal\simpletest\WebTestBase;
use Drupal\Core\Datetime\DrupalDateTime;

/**
 * Tests Datetime field functionality.
17 18
 *
 * @group datetime
19
 */
20
class DateTimeFieldTest extends WebTestBase {
21 22 23 24 25 26

  /**
   * Modules to enable.
   *
   * @var array
   */
27
  public static $modules = array('node', 'entity_test', 'datetime', 'field_ui');
28 29

  /**
30
   * A field storage to use in this test class.
31
   *
32
   * @var \Drupal\field\Entity\FieldStorageConfig
33
   */
34
  protected $fieldStorage;
35

36
  /**
37
   * The field used in this test class.
38
   *
39
   * @var \Drupal\field\Entity\FieldConfig
40
   */
41
  protected $field;
42

43
  protected function setUp() {
44 45 46
    parent::setUp();

    $web_user = $this->drupalCreateUser(array(
47
      'access content',
48 49
      'view test entity',
      'administer entity_test content',
50
      'administer content types',
51
      'administer node fields',
52 53 54 55
    ));
    $this->drupalLogin($web_user);

    // Create a field with settings to validate.
56
    $field_name = Unicode::strtolower($this->randomMachineName());
57
    $this->fieldStorage = entity_create('field_storage_config', array(
58
      'field_name' => $field_name,
59
      'entity_type' => 'entity_test',
60 61
      'type' => 'datetime',
      'settings' => array('datetime_type' => 'date'),
62
    ));
63
    $this->fieldStorage->save();
64
    $this->field = entity_create('field_config', array(
65
      'field_storage' => $this->fieldStorage,
66
      'bundle' => 'entity_test',
67
      'required' => TRUE,
68
    ));
69
    $this->field->save();
70

71
    entity_get_form_display($this->field->entity_type, $this->field->bundle, 'default')
72
      ->setComponent($field_name, array(
73 74 75 76
        'type' => 'datetime_default',
      ))
      ->save();

77 78 79 80 81
    $this->display_options = array(
      'type' => 'datetime_default',
      'label' => 'hidden',
      'settings' => array('format_type' => 'medium'),
    );
82
    entity_get_display($this->field->entity_type, $this->field->bundle, 'full')
83
      ->setComponent($field_name, $this->display_options)
84 85 86 87 88 89 90
      ->save();
  }

  /**
   * Tests date field functionality.
   */
  function testDateField() {
91
    $field_name = $this->fieldStorage->field_name;
92 93

    // Display creation form.
94
    $this->drupalGet('entity_test/add');
95
    $this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.');
96
    $this->assertFieldByXPath('//*[@id="edit-' . $field_name . '-wrapper"]/h4[contains(@class, "form-required")]', TRUE, 'Required markup found');
97
    $this->assertNoFieldByName("{$field_name}[0][value][time]", '', 'Time element not found.');
98 99 100 101

    // Submit a valid date and ensure it is accepted.
    $value = '2012-12-31 00:00:00';
    $date = new DrupalDateTime($value);
102 103
    $date_format = entity_load('date_format', 'html_date')->getPattern();
    $time_format = entity_load('date_format', 'html_time')->getPattern();
104 105

    $edit = array(
106
      "{$field_name}[0][value][date]" => $date->format($date_format),
107
    );
108
    $this->drupalPostForm(NULL, $edit, t('Save'));
109
    preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
110
    $id = $match[1];
111
    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
112 113 114 115 116 117 118 119 120 121 122 123 124 125
    $this->assertRaw($date->format($date_format));
    $this->assertNoRaw($date->format($time_format));

    // The expected values will use the default time.
    datetime_date_default_time($date);

    // Verify that the date is output according to the formatter settings.
    $options = array(
      'format_type' => array('short', 'medium', 'long'),
    );
    foreach ($options as $setting => $values) {
      foreach ($values as $new_value) {
        // Update the entity display settings.
        $this->display_options['settings'] = array($setting => $new_value);
126
        entity_get_display($this->field->entity_type, $this->field->bundle, 'full')
127
          ->setComponent($field_name, $this->display_options)
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
          ->save();

        $this->renderTestEntity($id);
        switch ($setting) {
          case 'format_type':
            // Verify that a date is displayed.
            $expected = format_date($date->getTimestamp(), $new_value);
            $this->renderTestEntity($id);
            $this->assertText($expected, format_string('Formatted date field using %value format displayed as %expected.', array('%value' => $new_value, '%expected' => $expected)));
            break;
        }
      }
    }

    // Verify that the plain formatter works.
    $this->display_options['type'] = 'datetime_plain';
144
    entity_get_display($this->field->entity_type, $this->field->bundle, 'full')
145
      ->setComponent($field_name, $this->display_options)
146 147 148 149 150 151 152 153 154 155
      ->save();
    $expected = $date->format(DATETIME_DATE_STORAGE_FORMAT);
    $this->renderTestEntity($id);
    $this->assertText($expected, format_string('Formatted date field using plain format displayed as %expected.', array('%expected' => $expected)));
  }

  /**
   * Tests date and time field.
   */
  function testDatetimeField() {
156
    $field_name = $this->fieldStorage->getName();
157
    // Change the field to a datetime field.
158 159
    $this->fieldStorage->settings['datetime_type'] = 'datetime';
    $this->fieldStorage->save();
160 161

    // Display creation form.
162
    $this->drupalGet('entity_test/add');
163 164
    $this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.');
    $this->assertFieldByName("{$field_name}[0][value][time]", '', 'Time element found.');
165 166 167 168

    // Submit a valid date and ensure it is accepted.
    $value = '2012-12-31 00:00:00';
    $date = new DrupalDateTime($value);
169 170
    $date_format = entity_load('date_format', 'html_date')->getPattern();
    $time_format = entity_load('date_format', 'html_time')->getPattern();
171 172

    $edit = array(
173 174
      "{$field_name}[0][value][date]" => $date->format($date_format),
      "{$field_name}[0][value][time]" => $date->format($time_format),
175
    );
176
    $this->drupalPostForm(NULL, $edit, t('Save'));
177
    preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
178
    $id = $match[1];
179
    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
180 181 182 183 184 185 186 187 188 189 190
    $this->assertRaw($date->format($date_format));
    $this->assertRaw($date->format($time_format));

    // Verify that the date is output according to the formatter settings.
    $options = array(
      'format_type' => array('short', 'medium', 'long'),
    );
    foreach ($options as $setting => $values) {
      foreach ($values as $new_value) {
        // Update the entity display settings.
        $this->display_options['settings'] = array($setting => $new_value);
191
        entity_get_display($this->field->entity_type, $this->field->bundle, 'full')
192
          ->setComponent($field_name, $this->display_options)
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
          ->save();

        $this->renderTestEntity($id);
        switch ($setting) {
          case 'format_type':
            // Verify that a date is displayed.
            $expected = format_date($date->getTimestamp(), $new_value);
            $this->renderTestEntity($id);
            $this->assertText($expected, format_string('Formatted date field using %value format displayed as %expected.', array('%value' => $new_value, '%expected' => $expected)));
            break;
        }
      }
    }

    // Verify that the plain formatter works.
    $this->display_options['type'] = 'datetime_plain';
209
    entity_get_display($this->field->entity_type, $this->field->bundle, 'full')
210
      ->setComponent($field_name, $this->display_options)
211 212 213 214 215 216 217 218 219 220
      ->save();
    $expected = $date->format(DATETIME_DATETIME_STORAGE_FORMAT);
    $this->renderTestEntity($id);
    $this->assertText($expected, format_string('Formatted date field using plain format displayed as %expected.', array('%expected' => $expected)));
  }

  /**
   * Tests Date List Widget functionality.
   */
  function testDatelistWidget() {
221
    $field_name = $this->fieldStorage->getName();
222
    // Change the field to a datetime field.
223 224
    $this->fieldStorage->settings['datetime_type'] = 'datetime';
    $this->fieldStorage->save();
225 226

    // Change the widget to a datelist widget.
227
    entity_get_form_display($this->field->entity_type, $this->field->bundle, 'default')
228
      ->setComponent($field_name, array(
229 230 231 232 233 234 235 236
        'type' => 'datetime_datelist',
        'settings' => array(
          'increment' => 1,
          'date_order' => 'YMD',
          'time_type' => '12',
        ),
      ))
      ->save();
237
    \Drupal::entityManager()->clearCachedFieldDefinitions();
238 239

    // Display creation form.
240
    $this->drupalGet('entity_test/add');
241 242 243 244 245 246 247 248 249 250 251 252 253 254

    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-year\"]", NULL, 'Year element found.');
    $this->assertOptionSelected("edit-$field_name-0-value-year", '', 'No year selected.');
    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-month\"]", NULL, 'Month element found.');
    $this->assertOptionSelected("edit-$field_name-0-value-month", '', 'No month selected.');
    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-day\"]", NULL, 'Day element found.');
    $this->assertOptionSelected("edit-$field_name-0-value-day", '', 'No day selected.');
    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-hour\"]", NULL, 'Hour element found.');
    $this->assertOptionSelected("edit-$field_name-0-value-hour", '', 'No hour selected.');
    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-minute\"]", NULL, 'Minute element found.');
    $this->assertOptionSelected("edit-$field_name-0-value-minute", '', 'No minute selected.');
    $this->assertNoFieldByXPath("//*[@id=\"edit-$field_name-0-value-second\"]", NULL, 'Second element not found.');
    $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-ampm\"]", NULL, 'AMPM element found.');
    $this->assertOptionSelected("edit-$field_name-0-value-ampm", '', 'No ampm selected.');
255 256 257 258

    // Submit a valid date and ensure it is accepted.
    $date_value = array('year' => 2012, 'month' => 12, 'day' => 31, 'hour' => 5, 'minute' => 15);

259
    $edit = array();
260 261 262
    // Add the ampm indicator since we are testing 12 hour time.
    $date_value['ampm'] = 'am';
    foreach ($date_value as $part => $value) {
263
      $edit["{$field_name}[0][value][$part]"] = $value;
264 265
    }

266
    $this->drupalPostForm(NULL, $edit, t('Save'));
267
    preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
268
    $id = $match[1];
269
    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
270

271 272 273 274 275 276
    $this->assertOptionSelected("edit-$field_name-0-value-year", '2012', 'Correct year selected.');
    $this->assertOptionSelected("edit-$field_name-0-value-month", '12', 'Correct month selected.');
    $this->assertOptionSelected("edit-$field_name-0-value-day", '31', 'Correct day selected.');
    $this->assertOptionSelected("edit-$field_name-0-value-hour", '5', 'Correct hour selected.');
    $this->assertOptionSelected("edit-$field_name-0-value-minute", '15', 'Correct minute selected.');
    $this->assertOptionSelected("edit-$field_name-0-value-ampm", 'am', 'Correct ampm selected.');
277 278 279 280 281 282
  }

  /**
   * Test default value functionality.
   */
  function testDefaultValue() {
283 284
    // Create a test content type.
    $this->drupalCreateContentType(array('type' => 'date_content'));
285

286
    // Create a field storage with settings to validate.
287
    $field_name = Unicode::strtolower($this->randomMachineName());
288
    $field_storage = entity_create('field_storage_config', array(
289
      'field_name' => $field_name,
290 291 292 293
      'entity_type' => 'node',
      'type' => 'datetime',
      'settings' => array('datetime_type' => 'date'),
    ));
294
    $field_storage->save();
295

296
    $field = entity_create('field_config', array(
297
      'field_storage' => $field_storage,
298 299
      'bundle' => 'date_content',
    ));
300
    $field->save();
301

302
    // Set now as default_value.
303
    $field_edit = array(
304
      'default_value_input[default_date_type]' => 'now',
305
    );
306
    $this->drupalPostForm('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name, $field_edit, t('Save settings'));
307

308
    // Check that default value is selected in default value form.
309
    $this->drupalGet('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name);
310 311
    $this->assertOptionSelected('edit-default-value-input-default-date-type', 'now', 'The default value is selected in instance settings page');
    $this->assertFieldByName('default_value_input[default_date]', '', 'The relative default value is empty in instance settings page');
312

313
    // Check if default_date has been stored successfully.
314
    $config_entity = $this->container->get('config.factory')->get('field.field.node.date_content.' . $field_name)->get();
315
    $this->assertEqual($config_entity['default_value'][0], array('default_date_type' => 'now', 'default_date' => 'now'), 'Default value has been stored successfully');
316

317 318
    // Clear field cache in order to avoid stale cache values.
    \Drupal::entityManager()->clearCachedFieldDefinitions();
319

320 321 322
    // Create a new node to check that datetime field default value is today.
    $new_node = entity_create('node', array('type' => 'date_content'));
    $expected_date = new DrupalDateTime('now', DATETIME_STORAGE_TIMEZONE);
323
    $this->assertEqual($new_node->get($field_name)->offsetGet(0)->value, $expected_date->format(DATETIME_DATE_STORAGE_FORMAT));
324

325
    // Set an invalid relative default_value to test validation.
326
    $field_edit = array(
327 328 329
      'default_value_input[default_date_type]' => 'relative',
      'default_value_input[default_date]' => 'invalid date',
    );
330
    $this->drupalPostForm('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name, $field_edit, t('Save settings'));
331 332 333 334

    $this->assertText('The relative date value entered is invalid.');

    // Set a relative default_value.
335
    $field_edit = array(
336 337 338
      'default_value_input[default_date_type]' => 'relative',
      'default_value_input[default_date]' => '+90 days',
    );
339
    $this->drupalPostForm('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name, $field_edit, t('Save settings'));
340 341

    // Check that default value is selected in default value form.
342
    $this->drupalGet('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name);
343 344 345 346
    $this->assertOptionSelected('edit-default-value-input-default-date-type', 'relative', 'The default value is selected in instance settings page');
    $this->assertFieldByName('default_value_input[default_date]', '+90 days', 'The relative default value is displayed in instance settings page');

    // Check if default_date has been stored successfully.
347
    $config_entity = $this->container->get('config.factory')->get('field.field.node.date_content.' . $field_name)->get();
348 349 350 351 352 353 354 355
    $this->assertEqual($config_entity['default_value'][0], array('default_date_type' => 'relative', 'default_date' => '+90 days'), 'Default value has been stored successfully');

    // Clear field cache in order to avoid stale cache values.
    \Drupal::entityManager()->clearCachedFieldDefinitions();

    // Create a new node to check that datetime field default value is +90 days.
    $new_node = entity_create('node', array('type' => 'date_content'));
    $expected_date = new DrupalDateTime('+90 days', DATETIME_STORAGE_TIMEZONE);
356
    $this->assertEqual($new_node->get($field_name)->offsetGet(0)->value, $expected_date->format(DATETIME_DATE_STORAGE_FORMAT));
357

358
    // Remove default value.
359
    $field_edit = array(
360
      'default_value_input[default_date_type]' => '',
361
    );
362
    $this->drupalPostForm('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name, $field_edit, t('Save settings'));
363 364

    // Check that default value is selected in default value form.
365
    $this->drupalGet('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name);
366 367
    $this->assertOptionSelected('edit-default-value-input-default-date-type', '', 'The default value is selected in instance settings page');
    $this->assertFieldByName('default_value_input[default_date]', '', 'The relative default value is empty in instance settings page');
368 369

    // Check if default_date has been stored successfully.
370
    $config_entity = $this->container->get('config.factory')->get('field.field.node.date_content.' . $field_name)->get();
371
    $this->assertTrue(empty($config_entity['default_value']), 'Empty default value has been stored successfully');
372

373 374
    // Clear field cache in order to avoid stale cache values.
    \Drupal::entityManager()->clearCachedFieldDefinitions();
375

376
    // Create a new node to check that datetime field default value is not set.
377
    $new_node = entity_create('node', array('type' => 'date_content'));
378
    $this->assertNull($new_node->get($field_name)->offsetGet(0)->value, 'Default value is not set');
379 380 381 382 383 384 385 386
  }

  /**
   * Test that invalid values are caught and marked as invalid.
   */
  function testInvalidField() {

    // Change the field to a datetime field.
387 388
    $this->fieldStorage->settings['datetime_type'] = 'datetime';
    $this->fieldStorage->save();
389
    $field_name = $this->fieldStorage->getName();
390 391

    // Display creation form.
392
    $this->drupalGet('entity_test/add');
393 394
    $this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.');
    $this->assertFieldByName("{$field_name}[0][value][time]", '', 'Time element found.');
395 396 397 398

    // Submit invalid dates and ensure they is not accepted.
    $date_value = '';
    $edit = array(
399 400
      "{$field_name}[0][value][date]" => $date_value,
      "{$field_name}[0][value][time]" => '12:00:00',
401
    );
402
    $this->drupalPostForm(NULL, $edit, t('Save'));
403 404 405 406
    $this->assertText('date is invalid', 'Empty date value has been caught.');

    $date_value = 'aaaa-12-01';
    $edit = array(
407 408
      "{$field_name}[0][value][date]" => $date_value,
      "{$field_name}[0][value][time]" => '00:00:00',
409
    );
410
    $this->drupalPostForm(NULL, $edit, t('Save'));
411 412 413 414
    $this->assertText('date is invalid', format_string('Invalid year value %date has been caught.', array('%date' => $date_value)));

    $date_value = '2012-75-01';
    $edit = array(
415 416
      "{$field_name}[0][value][date]" => $date_value,
      "{$field_name}[0][value][time]" => '00:00:00',
417
    );
418
    $this->drupalPostForm(NULL, $edit, t('Save'));
419 420 421 422
    $this->assertText('date is invalid', format_string('Invalid month value %date has been caught.', array('%date' => $date_value)));

    $date_value = '2012-12-99';
    $edit = array(
423 424
      "{$field_name}[0][value][date]" => $date_value,
      "{$field_name}[0][value][time]" => '00:00:00',
425
    );
426
    $this->drupalPostForm(NULL, $edit, t('Save'));
427 428 429 430 431
    $this->assertText('date is invalid', format_string('Invalid day value %date has been caught.', array('%date' => $date_value)));

    $date_value = '2012-12-01';
    $time_value = '';
    $edit = array(
432 433
      "{$field_name}[0][value][date]" => $date_value,
      "{$field_name}[0][value][time]" => $time_value,
434
    );
435
    $this->drupalPostForm(NULL, $edit, t('Save'));
436 437 438 439 440
    $this->assertText('date is invalid', 'Empty time value has been caught.');

    $date_value = '2012-12-01';
    $time_value = '49:00:00';
    $edit = array(
441 442
      "{$field_name}[0][value][date]" => $date_value,
      "{$field_name}[0][value][time]" => $time_value,
443
    );
444
    $this->drupalPostForm(NULL, $edit, t('Save'));
445 446 447 448 449
    $this->assertText('date is invalid', format_string('Invalid hour value %time has been caught.', array('%time' => $time_value)));

    $date_value = '2012-12-01';
    $time_value = '12:99:00';
    $edit = array(
450 451
      "{$field_name}[0][value][date]" => $date_value,
      "{$field_name}[0][value][time]" => $time_value,
452
    );
453
    $this->drupalPostForm(NULL, $edit, t('Save'));
454 455 456 457 458
    $this->assertText('date is invalid', format_string('Invalid minute value %time has been caught.', array('%time' => $time_value)));

    $date_value = '2012-12-01';
    $time_value = '12:15:99';
    $edit = array(
459 460
      "{$field_name}[0][value][date]" => $date_value,
      "{$field_name}[0][value][time]" => $time_value,
461
    );
462
    $this->drupalPostForm(NULL, $edit, t('Save'));
463 464 465 466
    $this->assertText('date is invalid', format_string('Invalid second value %time has been caught.', array('%time' => $time_value)));
  }

  /**
467
   * Renders a entity_test and sets the output in the internal browser.
468 469
   *
   * @param int $id
470
   *   The entity_test ID to render.
471 472 473
   * @param string $view_mode
   *   (optional) The view mode to use for rendering. Defaults to 'full'.
   * @param bool $reset
474
   *   (optional) Whether to reset the entity_test controller cache. Defaults to
475 476 477 478
   *   TRUE to simplify testing.
   */
  protected function renderTestEntity($id, $view_mode = 'full', $reset = TRUE) {
    if ($reset) {
479
      \Drupal::entityManager()->getStorage('entity_test')->resetCache(array($id));
480
    }
481
    $entity = entity_load('entity_test', $id);
482
    $display = EntityViewDisplay::collectRenderDisplay($entity, $view_mode);
483 484
    $build = $display->build($entity);
    $output = drupal_render($build);
485 486 487 488 489
    $this->drupalSetContent($output);
    $this->verbose($output);
  }

}