Mercurial > hg > isophonics-drupal-site
comparison core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Tests\datetime\Functional; | |
4 | |
5 use Drupal\Component\Render\FormattableMarkup; | |
6 use Drupal\Component\Utility\SafeMarkup; | |
7 use Drupal\Component\Utility\Unicode; | |
8 use Drupal\Core\Datetime\DrupalDateTime; | |
9 use Drupal\Core\Datetime\Entity\DateFormat; | |
10 use Drupal\entity_test\Entity\EntityTest; | |
11 use Drupal\field\Entity\FieldConfig; | |
12 use Drupal\field\Entity\FieldStorageConfig; | |
13 use Drupal\node\Entity\Node; | |
14 | |
15 /** | |
16 * Tests Datetime field functionality. | |
17 * | |
18 * @group datetime | |
19 */ | |
20 class DateTimeFieldTest extends DateTestBase { | |
21 | |
22 /** | |
23 * The default display settings to use for the formatters. | |
24 * | |
25 * @var array | |
26 */ | |
27 protected $defaultSettings = ['timezone_override' => '']; | |
28 | |
29 /** | |
30 * {@inheritdoc} | |
31 */ | |
32 protected function getTestFieldType() { | |
33 return 'datetime'; | |
34 } | |
35 | |
36 /** | |
37 * Tests date field functionality. | |
38 */ | |
39 public function testDateField() { | |
40 $field_name = $this->fieldStorage->getName(); | |
41 | |
42 // Loop through defined timezones to test that date-only fields work at the | |
43 // extremes. | |
44 foreach (static::$timezones as $timezone) { | |
45 | |
46 $this->setSiteTimezone($timezone); | |
47 $this->assertEquals($timezone, $this->config('system.date')->get('timezone.default'), 'Time zone set to ' . $timezone); | |
48 | |
49 // Display creation form. | |
50 $this->drupalGet('entity_test/add'); | |
51 $this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.'); | |
52 $this->assertFieldByXPath('//*[@id="edit-' . $field_name . '-wrapper"]//label[contains(@class,"js-form-required")]', TRUE, 'Required markup found'); | |
53 $this->assertNoFieldByName("{$field_name}[0][value][time]", '', 'Time element not found.'); | |
54 $this->assertFieldByXPath('//input[@aria-describedby="edit-' . $field_name . '-0-value--description"]', NULL, 'ARIA described-by found'); | |
55 $this->assertFieldByXPath('//div[@id="edit-' . $field_name . '-0-value--description"]', NULL, 'ARIA description found'); | |
56 | |
57 // Build up a date in the UTC timezone. Note that using this will also | |
58 // mimic the user in a different timezone simply entering '2012-12-31' via | |
59 // the UI. | |
60 $value = '2012-12-31 00:00:00'; | |
61 $date = new DrupalDateTime($value, DATETIME_STORAGE_TIMEZONE); | |
62 | |
63 // Submit a valid date and ensure it is accepted. | |
64 $date_format = DateFormat::load('html_date')->getPattern(); | |
65 $time_format = DateFormat::load('html_time')->getPattern(); | |
66 | |
67 $edit = [ | |
68 "{$field_name}[0][value][date]" => $date->format($date_format), | |
69 ]; | |
70 $this->drupalPostForm(NULL, $edit, t('Save')); | |
71 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); | |
72 $id = $match[1]; | |
73 $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); | |
74 $this->assertRaw($date->format($date_format)); | |
75 $this->assertNoRaw($date->format($time_format)); | |
76 | |
77 // Verify the date doesn't change if using a timezone that is UTC+12 when | |
78 // the entity is edited through the form. | |
79 $entity = EntityTest::load($id); | |
80 $this->assertEqual('2012-12-31', $entity->{$field_name}->value); | |
81 $this->drupalGet('entity_test/manage/' . $id . '/edit'); | |
82 $this->drupalPostForm(NULL, [], t('Save')); | |
83 $this->drupalGet('entity_test/manage/' . $id . '/edit'); | |
84 $this->drupalPostForm(NULL, [], t('Save')); | |
85 $this->drupalGet('entity_test/manage/' . $id . '/edit'); | |
86 $this->drupalPostForm(NULL, [], t('Save')); | |
87 $entity = EntityTest::load($id); | |
88 $this->assertEqual('2012-12-31', $entity->{$field_name}->value); | |
89 | |
90 // Reset display options since these get changed below. | |
91 $this->displayOptions = [ | |
92 'type' => 'datetime_default', | |
93 'label' => 'hidden', | |
94 'settings' => ['format_type' => 'medium'] + $this->defaultSettings, | |
95 ]; | |
96 // Verify that the date is output according to the formatter settings. | |
97 $options = [ | |
98 'format_type' => ['short', 'medium', 'long'], | |
99 ]; | |
100 // Formats that display a time component for date-only fields will display | |
101 // the default time, so that is applied before calculating the expected | |
102 // value. | |
103 datetime_date_default_time($date); | |
104 foreach ($options as $setting => $values) { | |
105 foreach ($values as $new_value) { | |
106 // Update the entity display settings. | |
107 $this->displayOptions['settings'] = [$setting => $new_value] + $this->defaultSettings; | |
108 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
109 ->setComponent($field_name, $this->displayOptions) | |
110 ->save(); | |
111 | |
112 $this->renderTestEntity($id); | |
113 switch ($setting) { | |
114 case 'format_type': | |
115 // Verify that a date is displayed. Since this is a date-only | |
116 // field, it is expected to display the time as 00:00:00. | |
117 $expected = format_date($date->getTimestamp(), $new_value, '', DATETIME_STORAGE_TIMEZONE); | |
118 $expected_iso = format_date($date->getTimestamp(), 'custom', 'Y-m-d\TH:i:s\Z', DATETIME_STORAGE_TIMEZONE); | |
119 $output = $this->renderTestEntity($id); | |
120 $expected_markup = '<time datetime="' . $expected_iso . '" class="datetime">' . $expected . '</time>'; | |
121 $this->assertContains($expected_markup, $output, new FormattableMarkup('Formatted date field using %value format displayed as %expected with %expected_iso attribute in %timezone.', [ | |
122 '%value' => $new_value, | |
123 '%expected' => $expected, | |
124 '%expected_iso' => $expected_iso, | |
125 '%timezone' => $timezone, | |
126 ])); | |
127 break; | |
128 } | |
129 } | |
130 } | |
131 | |
132 // Verify that the plain formatter works. | |
133 $this->displayOptions['type'] = 'datetime_plain'; | |
134 $this->displayOptions['settings'] = $this->defaultSettings; | |
135 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
136 ->setComponent($field_name, $this->displayOptions) | |
137 ->save(); | |
138 $expected = $date->format(DATETIME_DATE_STORAGE_FORMAT); | |
139 $output = $this->renderTestEntity($id); | |
140 $this->assertContains($expected, $output, new FormattableMarkup('Formatted date field using plain format displayed as %expected in %timezone.', [ | |
141 '%expected' => $expected, | |
142 '%timezone' => $timezone, | |
143 ])); | |
144 | |
145 // Verify that the 'datetime_custom' formatter works. | |
146 $this->displayOptions['type'] = 'datetime_custom'; | |
147 $this->displayOptions['settings'] = ['date_format' => 'm/d/Y'] + $this->defaultSettings; | |
148 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
149 ->setComponent($field_name, $this->displayOptions) | |
150 ->save(); | |
151 $expected = $date->format($this->displayOptions['settings']['date_format']); | |
152 $output = $this->renderTestEntity($id); | |
153 $this->assertContains($expected, $output, new FormattableMarkup('Formatted date field using datetime_custom format displayed as %expected in %timezone.', [ | |
154 '%expected' => $expected, | |
155 '%timezone' => $timezone, | |
156 ])); | |
157 | |
158 // Test that allowed markup in custom format is preserved and XSS is | |
159 // removed. | |
160 $this->displayOptions['settings']['date_format'] = '\\<\\s\\t\\r\\o\\n\\g\\>m/d/Y\\<\\/\\s\\t\\r\\o\\n\\g\\>\\<\\s\\c\\r\\i\\p\\t\\>\\a\\l\\e\\r\\t\\(\\S\\t\\r\\i\\n\\g\\.\\f\\r\\o\\m\\C\\h\\a\\r\\C\\o\\d\\e\\(\\8\\8\\,\\8\\3\\,\\8\\3\\)\\)\\<\\/\\s\\c\\r\\i\\p\\t\\>'; | |
161 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
162 ->setComponent($field_name, $this->displayOptions) | |
163 ->save(); | |
164 $expected = '<strong>' . $date->format('m/d/Y') . '</strong>alert(String.fromCharCode(88,83,83))'; | |
165 $output = $this->renderTestEntity($id); | |
166 $this->assertContains($expected, $output, new FormattableMarkup('Formatted date field using daterange_custom format displayed as %expected in %timezone.', [ | |
167 '%expected' => $expected, | |
168 '%timezone' => $timezone, | |
169 ])); | |
170 | |
171 // Verify that the 'datetime_time_ago' formatter works for intervals in the | |
172 // past. First update the test entity so that the date difference always | |
173 // has the same interval. Since the database always stores UTC, and the | |
174 // interval will use this, force the test date to use UTC and not the local | |
175 // or user timezome. | |
176 $timestamp = REQUEST_TIME - 87654321; | |
177 $entity = EntityTest::load($id); | |
178 $field_name = $this->fieldStorage->getName(); | |
179 $date = DrupalDateTime::createFromTimestamp($timestamp, 'UTC'); | |
180 $entity->{$field_name}->value = $date->format($date_format); | |
181 $entity->save(); | |
182 | |
183 $this->displayOptions['type'] = 'datetime_time_ago'; | |
184 $this->displayOptions['settings'] = [ | |
185 'future_format' => '@interval in the future', | |
186 'past_format' => '@interval in the past', | |
187 'granularity' => 3, | |
188 ]; | |
189 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
190 ->setComponent($field_name, $this->displayOptions) | |
191 ->save(); | |
192 $expected = SafeMarkup::format($this->displayOptions['settings']['past_format'], [ | |
193 '@interval' => $this->dateFormatter->formatTimeDiffSince($timestamp, ['granularity' => $this->displayOptions['settings']['granularity']]) | |
194 ]); | |
195 $output = $this->renderTestEntity($id); | |
196 $this->assertContains((string) $expected, $output, new FormattableMarkup('Formatted date field using datetime_time_ago format displayed as %expected in %timezone.', [ | |
197 '%expected' => $expected, | |
198 '%timezone' => $timezone, | |
199 ])); | |
200 | |
201 // Verify that the 'datetime_time_ago' formatter works for intervals in the | |
202 // future. First update the test entity so that the date difference always | |
203 // has the same interval. Since the database always stores UTC, and the | |
204 // interval will use this, force the test date to use UTC and not the local | |
205 // or user timezome. | |
206 $timestamp = REQUEST_TIME + 87654321; | |
207 $entity = EntityTest::load($id); | |
208 $field_name = $this->fieldStorage->getName(); | |
209 $date = DrupalDateTime::createFromTimestamp($timestamp, 'UTC'); | |
210 $entity->{$field_name}->value = $date->format($date_format); | |
211 $entity->save(); | |
212 | |
213 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
214 ->setComponent($field_name, $this->displayOptions) | |
215 ->save(); | |
216 $expected = SafeMarkup::format($this->displayOptions['settings']['future_format'], [ | |
217 '@interval' => $this->dateFormatter->formatTimeDiffUntil($timestamp, ['granularity' => $this->displayOptions['settings']['granularity']]) | |
218 ]); | |
219 $output = $this->renderTestEntity($id); | |
220 $this->assertContains((string) $expected, $output, new FormattableMarkup('Formatted date field using datetime_time_ago format displayed as %expected in %timezone.', [ | |
221 '%expected' => $expected, | |
222 '%timezone' => $timezone, | |
223 ])); | |
224 } | |
225 } | |
226 | |
227 /** | |
228 * Tests date and time field. | |
229 */ | |
230 public function testDatetimeField() { | |
231 $field_name = $this->fieldStorage->getName(); | |
232 $field_label = $this->field->label(); | |
233 // Change the field to a datetime field. | |
234 $this->fieldStorage->setSetting('datetime_type', 'datetime'); | |
235 $this->fieldStorage->save(); | |
236 | |
237 // Display creation form. | |
238 $this->drupalGet('entity_test/add'); | |
239 $this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.'); | |
240 $this->assertFieldByName("{$field_name}[0][value][time]", '', 'Time element found.'); | |
241 $this->assertFieldByXPath('//fieldset[@id="edit-' . $field_name . '-0"]/legend', $field_label, 'Fieldset and label found'); | |
242 $this->assertFieldByXPath('//fieldset[@aria-describedby="edit-' . $field_name . '-0--description"]', NULL, 'ARIA described-by found'); | |
243 $this->assertFieldByXPath('//div[@id="edit-' . $field_name . '-0--description"]', NULL, 'ARIA description found'); | |
244 | |
245 // Build up a date in the UTC timezone. | |
246 $value = '2012-12-31 00:00:00'; | |
247 $date = new DrupalDateTime($value, 'UTC'); | |
248 | |
249 // Update the timezone to the system default. | |
250 $date->setTimezone(timezone_open(drupal_get_user_timezone())); | |
251 | |
252 // Submit a valid date and ensure it is accepted. | |
253 $date_format = DateFormat::load('html_date')->getPattern(); | |
254 $time_format = DateFormat::load('html_time')->getPattern(); | |
255 | |
256 $edit = [ | |
257 "{$field_name}[0][value][date]" => $date->format($date_format), | |
258 "{$field_name}[0][value][time]" => $date->format($time_format), | |
259 ]; | |
260 $this->drupalPostForm(NULL, $edit, t('Save')); | |
261 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); | |
262 $id = $match[1]; | |
263 $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); | |
264 $this->assertRaw($date->format($date_format)); | |
265 $this->assertRaw($date->format($time_format)); | |
266 | |
267 // Verify that the date is output according to the formatter settings. | |
268 $options = [ | |
269 'format_type' => ['short', 'medium', 'long'], | |
270 ]; | |
271 foreach ($options as $setting => $values) { | |
272 foreach ($values as $new_value) { | |
273 // Update the entity display settings. | |
274 $this->displayOptions['settings'] = [$setting => $new_value] + $this->defaultSettings; | |
275 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
276 ->setComponent($field_name, $this->displayOptions) | |
277 ->save(); | |
278 | |
279 $this->renderTestEntity($id); | |
280 switch ($setting) { | |
281 case 'format_type': | |
282 // Verify that a date is displayed. | |
283 $expected = format_date($date->getTimestamp(), $new_value); | |
284 $expected_iso = format_date($date->getTimestamp(), 'custom', 'Y-m-d\TH:i:s\Z', 'UTC'); | |
285 $output = $this->renderTestEntity($id); | |
286 $expected_markup = '<time datetime="' . $expected_iso . '" class="datetime">' . $expected . '</time>'; | |
287 $this->assertContains($expected_markup, $output, SafeMarkup::format('Formatted date field using %value format displayed as %expected with %expected_iso attribute.', ['%value' => $new_value, '%expected' => $expected, '%expected_iso' => $expected_iso])); | |
288 break; | |
289 } | |
290 } | |
291 } | |
292 | |
293 // Verify that the plain formatter works. | |
294 $this->displayOptions['type'] = 'datetime_plain'; | |
295 $this->displayOptions['settings'] = $this->defaultSettings; | |
296 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
297 ->setComponent($field_name, $this->displayOptions) | |
298 ->save(); | |
299 $expected = $date->format(DATETIME_DATETIME_STORAGE_FORMAT); | |
300 $output = $this->renderTestEntity($id); | |
301 $this->assertContains($expected, $output, SafeMarkup::format('Formatted date field using plain format displayed as %expected.', ['%expected' => $expected])); | |
302 | |
303 // Verify that the 'datetime_custom' formatter works. | |
304 $this->displayOptions['type'] = 'datetime_custom'; | |
305 $this->displayOptions['settings'] = ['date_format' => 'm/d/Y g:i:s A'] + $this->defaultSettings; | |
306 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
307 ->setComponent($field_name, $this->displayOptions) | |
308 ->save(); | |
309 $expected = $date->format($this->displayOptions['settings']['date_format']); | |
310 $output = $this->renderTestEntity($id); | |
311 $this->assertContains($expected, $output, SafeMarkup::format('Formatted date field using datetime_custom format displayed as %expected.', ['%expected' => $expected])); | |
312 | |
313 // Verify that the 'timezone_override' setting works. | |
314 $this->displayOptions['type'] = 'datetime_custom'; | |
315 $this->displayOptions['settings'] = ['date_format' => 'm/d/Y g:i:s A', 'timezone_override' => 'America/New_York'] + $this->defaultSettings; | |
316 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
317 ->setComponent($field_name, $this->displayOptions) | |
318 ->save(); | |
319 $expected = $date->format($this->displayOptions['settings']['date_format'], ['timezone' => 'America/New_York']); | |
320 $output = $this->renderTestEntity($id); | |
321 $this->assertContains($expected, $output, SafeMarkup::format('Formatted date field using datetime_custom format displayed as %expected.', ['%expected' => $expected])); | |
322 | |
323 // Verify that the 'datetime_time_ago' formatter works for intervals in the | |
324 // past. First update the test entity so that the date difference always | |
325 // has the same interval. Since the database always stores UTC, and the | |
326 // interval will use this, force the test date to use UTC and not the local | |
327 // or user timezome. | |
328 $timestamp = REQUEST_TIME - 87654321; | |
329 $entity = EntityTest::load($id); | |
330 $field_name = $this->fieldStorage->getName(); | |
331 $date = DrupalDateTime::createFromTimestamp($timestamp, 'UTC'); | |
332 $entity->{$field_name}->value = $date->format(DATETIME_DATETIME_STORAGE_FORMAT); | |
333 $entity->save(); | |
334 | |
335 $this->displayOptions['type'] = 'datetime_time_ago'; | |
336 $this->displayOptions['settings'] = [ | |
337 'future_format' => '@interval from now', | |
338 'past_format' => '@interval earlier', | |
339 'granularity' => 3, | |
340 ]; | |
341 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
342 ->setComponent($field_name, $this->displayOptions) | |
343 ->save(); | |
344 $expected = SafeMarkup::format($this->displayOptions['settings']['past_format'], [ | |
345 '@interval' => $this->dateFormatter->formatTimeDiffSince($timestamp, ['granularity' => $this->displayOptions['settings']['granularity']]) | |
346 ]); | |
347 $output = $this->renderTestEntity($id); | |
348 $this->assertContains((string) $expected, $output, SafeMarkup::format('Formatted date field using datetime_time_ago format displayed as %expected.', ['%expected' => $expected])); | |
349 | |
350 // Verify that the 'datetime_time_ago' formatter works for intervals in the | |
351 // future. First update the test entity so that the date difference always | |
352 // has the same interval. Since the database always stores UTC, and the | |
353 // interval will use this, force the test date to use UTC and not the local | |
354 // or user timezome. | |
355 $timestamp = REQUEST_TIME + 87654321; | |
356 $entity = EntityTest::load($id); | |
357 $field_name = $this->fieldStorage->getName(); | |
358 $date = DrupalDateTime::createFromTimestamp($timestamp, 'UTC'); | |
359 $entity->{$field_name}->value = $date->format(DATETIME_DATETIME_STORAGE_FORMAT); | |
360 $entity->save(); | |
361 | |
362 entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') | |
363 ->setComponent($field_name, $this->displayOptions) | |
364 ->save(); | |
365 $expected = SafeMarkup::format($this->displayOptions['settings']['future_format'], [ | |
366 '@interval' => $this->dateFormatter->formatTimeDiffUntil($timestamp, ['granularity' => $this->displayOptions['settings']['granularity']]) | |
367 ]); | |
368 $output = $this->renderTestEntity($id); | |
369 $this->assertContains((string) $expected, $output, SafeMarkup::format('Formatted date field using datetime_time_ago format displayed as %expected.', ['%expected' => $expected])); | |
370 } | |
371 | |
372 /** | |
373 * Tests Date List Widget functionality. | |
374 */ | |
375 public function testDatelistWidget() { | |
376 $field_name = $this->fieldStorage->getName(); | |
377 $field_label = $this->field->label(); | |
378 | |
379 // Ensure field is set to a date only field. | |
380 $this->fieldStorage->setSetting('datetime_type', 'date'); | |
381 $this->fieldStorage->save(); | |
382 | |
383 // Change the widget to a datelist widget. | |
384 entity_get_form_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'default') | |
385 ->setComponent($field_name, [ | |
386 'type' => 'datetime_datelist', | |
387 'settings' => [ | |
388 'date_order' => 'YMD', | |
389 ], | |
390 ]) | |
391 ->save(); | |
392 \Drupal::entityManager()->clearCachedFieldDefinitions(); | |
393 | |
394 // Display creation form. | |
395 $this->drupalGet('entity_test/add'); | |
396 $this->assertFieldByXPath('//fieldset[@id="edit-' . $field_name . '-0"]/legend', $field_label, 'Fieldset and label found'); | |
397 $this->assertFieldByXPath('//fieldset[@aria-describedby="edit-' . $field_name . '-0--description"]', NULL, 'ARIA described-by found'); | |
398 $this->assertFieldByXPath('//div[@id="edit-' . $field_name . '-0--description"]', NULL, 'ARIA description found'); | |
399 | |
400 // Assert that Hour and Minute Elements do not appear on Date Only | |
401 $this->assertNoFieldByXPath("//*[@id=\"edit-$field_name-0-value-hour\"]", NULL, 'Hour element not found on Date Only.'); | |
402 $this->assertNoFieldByXPath("//*[@id=\"edit-$field_name-0-value-minute\"]", NULL, 'Minute element not found on Date Only.'); | |
403 | |
404 // Go to the form display page to assert that increment option does not appear on Date Only | |
405 $fieldEditUrl = 'entity_test/structure/entity_test/form-display'; | |
406 $this->drupalGet($fieldEditUrl); | |
407 | |
408 // Click on the widget settings button to open the widget settings form. | |
409 $this->drupalPostForm(NULL, [], $field_name . "_settings_edit"); | |
410 $xpathIncr = "//select[starts-with(@id, \"edit-fields-$field_name-settings-edit-form-settings-increment\")]"; | |
411 $this->assertNoFieldByXPath($xpathIncr, NULL, 'Increment element not found for Date Only.'); | |
412 | |
413 // Change the field to a datetime field. | |
414 $this->fieldStorage->setSetting('datetime_type', 'datetime'); | |
415 $this->fieldStorage->save(); | |
416 | |
417 // Change the widget to a datelist widget. | |
418 entity_get_form_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'default') | |
419 ->setComponent($field_name, [ | |
420 'type' => 'datetime_datelist', | |
421 'settings' => [ | |
422 'increment' => 1, | |
423 'date_order' => 'YMD', | |
424 'time_type' => '12', | |
425 ], | |
426 ]) | |
427 ->save(); | |
428 \Drupal::entityManager()->clearCachedFieldDefinitions(); | |
429 | |
430 // Go to the form display page to assert that increment option does appear on Date Time | |
431 $fieldEditUrl = 'entity_test/structure/entity_test/form-display'; | |
432 $this->drupalGet($fieldEditUrl); | |
433 | |
434 // Click on the widget settings button to open the widget settings form. | |
435 $this->drupalPostForm(NULL, [], $field_name . "_settings_edit"); | |
436 $this->assertFieldByXPath($xpathIncr, NULL, 'Increment element found for Date and time.'); | |
437 | |
438 // Display creation form. | |
439 $this->drupalGet('entity_test/add'); | |
440 | |
441 $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-year\"]", NULL, 'Year element found.'); | |
442 $this->assertOptionSelected("edit-$field_name-0-value-year", '', 'No year selected.'); | |
443 $this->assertOptionByText("edit-$field_name-0-value-year", t('Year')); | |
444 $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-month\"]", NULL, 'Month element found.'); | |
445 $this->assertOptionSelected("edit-$field_name-0-value-month", '', 'No month selected.'); | |
446 $this->assertOptionByText("edit-$field_name-0-value-month", t('Month')); | |
447 $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-day\"]", NULL, 'Day element found.'); | |
448 $this->assertOptionSelected("edit-$field_name-0-value-day", '', 'No day selected.'); | |
449 $this->assertOptionByText("edit-$field_name-0-value-day", t('Day')); | |
450 $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-hour\"]", NULL, 'Hour element found.'); | |
451 $this->assertOptionSelected("edit-$field_name-0-value-hour", '', 'No hour selected.'); | |
452 $this->assertOptionByText("edit-$field_name-0-value-hour", t('Hour')); | |
453 $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-minute\"]", NULL, 'Minute element found.'); | |
454 $this->assertOptionSelected("edit-$field_name-0-value-minute", '', 'No minute selected.'); | |
455 $this->assertOptionByText("edit-$field_name-0-value-minute", t('Minute')); | |
456 $this->assertNoFieldByXPath("//*[@id=\"edit-$field_name-0-value-second\"]", NULL, 'Second element not found.'); | |
457 $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-ampm\"]", NULL, 'AMPM element found.'); | |
458 $this->assertOptionSelected("edit-$field_name-0-value-ampm", '', 'No ampm selected.'); | |
459 $this->assertOptionByText("edit-$field_name-0-value-ampm", t('AM/PM')); | |
460 | |
461 // Submit a valid date and ensure it is accepted. | |
462 $date_value = ['year' => 2012, 'month' => 12, 'day' => 31, 'hour' => 5, 'minute' => 15]; | |
463 | |
464 $edit = []; | |
465 // Add the ampm indicator since we are testing 12 hour time. | |
466 $date_value['ampm'] = 'am'; | |
467 foreach ($date_value as $part => $value) { | |
468 $edit["{$field_name}[0][value][$part]"] = $value; | |
469 } | |
470 | |
471 $this->drupalPostForm(NULL, $edit, t('Save')); | |
472 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); | |
473 $id = $match[1]; | |
474 $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); | |
475 | |
476 $this->assertOptionSelected("edit-$field_name-0-value-year", '2012', 'Correct year selected.'); | |
477 $this->assertOptionSelected("edit-$field_name-0-value-month", '12', 'Correct month selected.'); | |
478 $this->assertOptionSelected("edit-$field_name-0-value-day", '31', 'Correct day selected.'); | |
479 $this->assertOptionSelected("edit-$field_name-0-value-hour", '5', 'Correct hour selected.'); | |
480 $this->assertOptionSelected("edit-$field_name-0-value-minute", '15', 'Correct minute selected.'); | |
481 $this->assertOptionSelected("edit-$field_name-0-value-ampm", 'am', 'Correct ampm selected.'); | |
482 | |
483 // Test the widget using increment other than 1 and 24 hour mode. | |
484 entity_get_form_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'default') | |
485 ->setComponent($field_name, [ | |
486 'type' => 'datetime_datelist', | |
487 'settings' => [ | |
488 'increment' => 15, | |
489 'date_order' => 'YMD', | |
490 'time_type' => '24', | |
491 ], | |
492 ]) | |
493 ->save(); | |
494 \Drupal::entityManager()->clearCachedFieldDefinitions(); | |
495 | |
496 // Display creation form. | |
497 $this->drupalGet('entity_test/add'); | |
498 | |
499 // Other elements are unaffected by the changed settings. | |
500 $this->assertFieldByXPath("//*[@id=\"edit-$field_name-0-value-hour\"]", NULL, 'Hour element found.'); | |
501 $this->assertOptionSelected("edit-$field_name-0-value-hour", '', 'No hour selected.'); | |
502 $this->assertNoFieldByXPath("//*[@id=\"edit-$field_name-0-value-ampm\"]", NULL, 'AMPM element not found.'); | |
503 | |
504 // Submit a valid date and ensure it is accepted. | |
505 $date_value = ['year' => 2012, 'month' => 12, 'day' => 31, 'hour' => 17, 'minute' => 15]; | |
506 | |
507 $edit = []; | |
508 foreach ($date_value as $part => $value) { | |
509 $edit["{$field_name}[0][value][$part]"] = $value; | |
510 } | |
511 | |
512 $this->drupalPostForm(NULL, $edit, t('Save')); | |
513 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); | |
514 $id = $match[1]; | |
515 $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); | |
516 | |
517 $this->assertOptionSelected("edit-$field_name-0-value-year", '2012', 'Correct year selected.'); | |
518 $this->assertOptionSelected("edit-$field_name-0-value-month", '12', 'Correct month selected.'); | |
519 $this->assertOptionSelected("edit-$field_name-0-value-day", '31', 'Correct day selected.'); | |
520 $this->assertOptionSelected("edit-$field_name-0-value-hour", '17', 'Correct hour selected.'); | |
521 $this->assertOptionSelected("edit-$field_name-0-value-minute", '15', 'Correct minute selected.'); | |
522 | |
523 // Test the widget for partial completion of fields. | |
524 entity_get_form_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'default') | |
525 ->setComponent($field_name, [ | |
526 'type' => 'datetime_datelist', | |
527 'settings' => [ | |
528 'increment' => 1, | |
529 'date_order' => 'YMD', | |
530 'time_type' => '24', | |
531 ], | |
532 ]) | |
533 ->save(); | |
534 \Drupal::entityManager()->clearCachedFieldDefinitions(); | |
535 | |
536 // Test the widget for validation notifications. | |
537 foreach ($this->datelistDataProvider($field_label) as $data) { | |
538 list($date_value, $expected) = $data; | |
539 | |
540 // Display creation form. | |
541 $this->drupalGet('entity_test/add'); | |
542 | |
543 // Submit a partial date and ensure and error message is provided. | |
544 $edit = []; | |
545 foreach ($date_value as $part => $value) { | |
546 $edit["{$field_name}[0][value][$part]"] = $value; | |
547 } | |
548 | |
549 $this->drupalPostForm(NULL, $edit, t('Save')); | |
550 $this->assertResponse(200); | |
551 foreach ($expected as $expected_text) { | |
552 $this->assertText(t($expected_text)); | |
553 } | |
554 } | |
555 | |
556 // Test the widget for complete input with zeros as part of selections. | |
557 $this->drupalGet('entity_test/add'); | |
558 | |
559 $date_value = ['year' => 2012, 'month' => '12', 'day' => '31', 'hour' => '0', 'minute' => '0']; | |
560 $edit = []; | |
561 foreach ($date_value as $part => $value) { | |
562 $edit["{$field_name}[0][value][$part]"] = $value; | |
563 } | |
564 | |
565 $this->drupalPostForm(NULL, $edit, t('Save')); | |
566 $this->assertResponse(200); | |
567 preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); | |
568 $id = $match[1]; | |
569 $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); | |
570 | |
571 // Test the widget to ensure zeros are not deselected on validation. | |
572 $this->drupalGet('entity_test/add'); | |
573 | |
574 $date_value = ['year' => 2012, 'month' => '12', 'day' => '31', 'hour' => '', 'minute' => '0']; | |
575 $edit = []; | |
576 foreach ($date_value as $part => $value) { | |
577 $edit["{$field_name}[0][value][$part]"] = $value; | |
578 } | |
579 | |
580 $this->drupalPostForm(NULL, $edit, t('Save')); | |
581 $this->assertResponse(200); | |
582 $this->assertOptionSelected("edit-$field_name-0-value-minute", '0', 'Correct minute selected.'); | |
583 } | |
584 | |
585 /** | |
586 * The data provider for testing the validation of the datelist widget. | |
587 * | |
588 * @param string $field_label | |
589 * The label of the field being tested. | |
590 * | |
591 * @return array | |
592 * An array of datelist input permutations to test. | |
593 */ | |
594 protected function datelistDataProvider($field_label) { | |
595 return [ | |
596 // Nothing selected. | |
597 [ | |
598 ['year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => ''], | |
599 ["The $field_label date is required."], | |
600 ], | |
601 // Year only selected, validation error on Month, Day, Hour, Minute. | |
602 [ | |
603 ['year' => 2012, 'month' => '', 'day' => '', 'hour' => '', 'minute' => ''], | |
604 [ | |
605 "The $field_label date is incomplete.", | |
606 'A value must be selected for month.', | |
607 'A value must be selected for day.', | |
608 'A value must be selected for hour.', | |
609 'A value must be selected for minute.', | |
610 ], | |
611 ], | |
612 // Year and Month selected, validation error on Day, Hour, Minute. | |
613 [ | |
614 ['year' => 2012, 'month' => '12', 'day' => '', 'hour' => '', 'minute' => ''], | |
615 [ | |
616 "The $field_label date is incomplete.", | |
617 'A value must be selected for day.', | |
618 'A value must be selected for hour.', | |
619 'A value must be selected for minute.', | |
620 ], | |
621 ], | |
622 // Year, Month and Day selected, validation error on Hour, Minute. | |
623 [ | |
624 ['year' => 2012, 'month' => '12', 'day' => '31', 'hour' => '', 'minute' => ''], | |
625 [ | |
626 "The $field_label date is incomplete.", | |
627 'A value must be selected for hour.', | |
628 'A value must be selected for minute.', | |
629 ], | |
630 ], | |
631 // Year, Month, Day and Hour selected, validation error on Minute only. | |
632 [ | |
633 ['year' => 2012, 'month' => '12', 'day' => '31', 'hour' => '0', 'minute' => ''], | |
634 [ | |
635 "The $field_label date is incomplete.", | |
636 'A value must be selected for minute.', | |
637 ], | |
638 ], | |
639 ]; | |
640 } | |
641 | |
642 /** | |
643 * Test default value functionality. | |
644 */ | |
645 public function testDefaultValue() { | |
646 // Create a test content type. | |
647 $this->drupalCreateContentType(['type' => 'date_content']); | |
648 | |
649 // Create a field storage with settings to validate. | |
650 $field_name = Unicode::strtolower($this->randomMachineName()); | |
651 $field_storage = FieldStorageConfig::create([ | |
652 'field_name' => $field_name, | |
653 'entity_type' => 'node', | |
654 'type' => 'datetime', | |
655 'settings' => ['datetime_type' => 'date'], | |
656 ]); | |
657 $field_storage->save(); | |
658 | |
659 $field = FieldConfig::create([ | |
660 'field_storage' => $field_storage, | |
661 'bundle' => 'date_content', | |
662 ]); | |
663 $field->save(); | |
664 | |
665 // Loop through defined timezones to test that date-only defaults work at | |
666 // the extremes. | |
667 foreach (static::$timezones as $timezone) { | |
668 | |
669 $this->setSiteTimezone($timezone); | |
670 $this->assertEquals($timezone, $this->config('system.date')->get('timezone.default'), 'Time zone set to ' . $timezone); | |
671 | |
672 // Set now as default_value. | |
673 $field_edit = [ | |
674 'default_value_input[default_date_type]' => 'now', | |
675 ]; | |
676 $this->drupalPostForm('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name, $field_edit, t('Save settings')); | |
677 | |
678 // Check that default value is selected in default value form. | |
679 $this->drupalGet('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name); | |
680 $this->assertOptionSelected('edit-default-value-input-default-date-type', 'now', 'The default value is selected in instance settings page'); | |
681 $this->assertFieldByName('default_value_input[default_date]', '', 'The relative default value is empty in instance settings page'); | |
682 | |
683 // Check if default_date has been stored successfully. | |
684 $config_entity = $this->config('field.field.node.date_content.' . $field_name) | |
685 ->get(); | |
686 $this->assertEqual($config_entity['default_value'][0], [ | |
687 'default_date_type' => 'now', | |
688 'default_date' => 'now', | |
689 ], 'Default value has been stored successfully'); | |
690 | |
691 // Clear field cache in order to avoid stale cache values. | |
692 \Drupal::entityManager()->clearCachedFieldDefinitions(); | |
693 | |
694 // Create a new node to check that datetime field default value is today. | |
695 $new_node = Node::create(['type' => 'date_content']); | |
696 $expected_date = new DrupalDateTime('now', drupal_get_user_timezone()); | |
697 $this->assertEqual($new_node->get($field_name) | |
698 ->offsetGet(0)->value, $expected_date->format(DATETIME_DATE_STORAGE_FORMAT)); | |
699 | |
700 // Set an invalid relative default_value to test validation. | |
701 $field_edit = [ | |
702 'default_value_input[default_date_type]' => 'relative', | |
703 'default_value_input[default_date]' => 'invalid date', | |
704 ]; | |
705 $this->drupalPostForm('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name, $field_edit, t('Save settings')); | |
706 | |
707 $this->assertText('The relative date value entered is invalid.'); | |
708 | |
709 // Set a relative default_value. | |
710 $field_edit = [ | |
711 'default_value_input[default_date_type]' => 'relative', | |
712 'default_value_input[default_date]' => '+90 days', | |
713 ]; | |
714 $this->drupalPostForm('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name, $field_edit, t('Save settings')); | |
715 | |
716 // Check that default value is selected in default value form. | |
717 $this->drupalGet('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name); | |
718 $this->assertOptionSelected('edit-default-value-input-default-date-type', 'relative', 'The default value is selected in instance settings page'); | |
719 $this->assertFieldByName('default_value_input[default_date]', '+90 days', 'The relative default value is displayed in instance settings page'); | |
720 | |
721 // Check if default_date has been stored successfully. | |
722 $config_entity = $this->config('field.field.node.date_content.' . $field_name) | |
723 ->get(); | |
724 $this->assertEqual($config_entity['default_value'][0], [ | |
725 'default_date_type' => 'relative', | |
726 'default_date' => '+90 days', | |
727 ], 'Default value has been stored successfully'); | |
728 | |
729 // Clear field cache in order to avoid stale cache values. | |
730 \Drupal::entityManager()->clearCachedFieldDefinitions(); | |
731 | |
732 // Create a new node to check that datetime field default value is +90 | |
733 // days. | |
734 $new_node = Node::create(['type' => 'date_content']); | |
735 $expected_date = new DrupalDateTime('+90 days', drupal_get_user_timezone()); | |
736 $this->assertEqual($new_node->get($field_name) | |
737 ->offsetGet(0)->value, $expected_date->format(DATETIME_DATE_STORAGE_FORMAT)); | |
738 | |
739 // Remove default value. | |
740 $field_edit = [ | |
741 'default_value_input[default_date_type]' => '', | |
742 ]; | |
743 $this->drupalPostForm('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name, $field_edit, t('Save settings')); | |
744 | |
745 // Check that default value is selected in default value form. | |
746 $this->drupalGet('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name); | |
747 $this->assertOptionSelected('edit-default-value-input-default-date-type', '', 'The default value is selected in instance settings page'); | |
748 $this->assertFieldByName('default_value_input[default_date]', '', 'The relative default value is empty in instance settings page'); | |
749 | |
750 // Check if default_date has been stored successfully. | |
751 $config_entity = $this->config('field.field.node.date_content.' . $field_name) | |
752 ->get(); | |
753 $this->assertTrue(empty($config_entity['default_value']), 'Empty default value has been stored successfully'); | |
754 | |
755 // Clear field cache in order to avoid stale cache values. | |
756 \Drupal::entityManager()->clearCachedFieldDefinitions(); | |
757 | |
758 // Create a new node to check that datetime field default value is not | |
759 // set. | |
760 $new_node = Node::create(['type' => 'date_content']); | |
761 $this->assertNull($new_node->get($field_name)->value, 'Default value is not set'); | |
762 } | |
763 } | |
764 | |
765 /** | |
766 * Test that invalid values are caught and marked as invalid. | |
767 */ | |
768 public function testInvalidField() { | |
769 // Change the field to a datetime field. | |
770 $this->fieldStorage->setSetting('datetime_type', 'datetime'); | |
771 $this->fieldStorage->save(); | |
772 $field_name = $this->fieldStorage->getName(); | |
773 | |
774 // Display creation form. | |
775 $this->drupalGet('entity_test/add'); | |
776 $this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.'); | |
777 $this->assertFieldByName("{$field_name}[0][value][time]", '', 'Time element found.'); | |
778 | |
779 // Submit invalid dates and ensure they is not accepted. | |
780 $date_value = ''; | |
781 $edit = [ | |
782 "{$field_name}[0][value][date]" => $date_value, | |
783 "{$field_name}[0][value][time]" => '12:00:00', | |
784 ]; | |
785 $this->drupalPostForm(NULL, $edit, t('Save')); | |
786 $this->assertText('date is invalid', 'Empty date value has been caught.'); | |
787 | |
788 $date_value = 'aaaa-12-01'; | |
789 $edit = [ | |
790 "{$field_name}[0][value][date]" => $date_value, | |
791 "{$field_name}[0][value][time]" => '00:00:00', | |
792 ]; | |
793 $this->drupalPostForm(NULL, $edit, t('Save')); | |
794 $this->assertText('date is invalid', format_string('Invalid year value %date has been caught.', ['%date' => $date_value])); | |
795 | |
796 $date_value = '2012-75-01'; | |
797 $edit = [ | |
798 "{$field_name}[0][value][date]" => $date_value, | |
799 "{$field_name}[0][value][time]" => '00:00:00', | |
800 ]; | |
801 $this->drupalPostForm(NULL, $edit, t('Save')); | |
802 $this->assertText('date is invalid', format_string('Invalid month value %date has been caught.', ['%date' => $date_value])); | |
803 | |
804 $date_value = '2012-12-99'; | |
805 $edit = [ | |
806 "{$field_name}[0][value][date]" => $date_value, | |
807 "{$field_name}[0][value][time]" => '00:00:00', | |
808 ]; | |
809 $this->drupalPostForm(NULL, $edit, t('Save')); | |
810 $this->assertText('date is invalid', format_string('Invalid day value %date has been caught.', ['%date' => $date_value])); | |
811 | |
812 $date_value = '2012-12-01'; | |
813 $time_value = ''; | |
814 $edit = [ | |
815 "{$field_name}[0][value][date]" => $date_value, | |
816 "{$field_name}[0][value][time]" => $time_value, | |
817 ]; | |
818 $this->drupalPostForm(NULL, $edit, t('Save')); | |
819 $this->assertText('date is invalid', 'Empty time value has been caught.'); | |
820 | |
821 $date_value = '2012-12-01'; | |
822 $time_value = '49:00:00'; | |
823 $edit = [ | |
824 "{$field_name}[0][value][date]" => $date_value, | |
825 "{$field_name}[0][value][time]" => $time_value, | |
826 ]; | |
827 $this->drupalPostForm(NULL, $edit, t('Save')); | |
828 $this->assertText('date is invalid', format_string('Invalid hour value %time has been caught.', ['%time' => $time_value])); | |
829 | |
830 $date_value = '2012-12-01'; | |
831 $time_value = '12:99:00'; | |
832 $edit = [ | |
833 "{$field_name}[0][value][date]" => $date_value, | |
834 "{$field_name}[0][value][time]" => $time_value, | |
835 ]; | |
836 $this->drupalPostForm(NULL, $edit, t('Save')); | |
837 $this->assertText('date is invalid', format_string('Invalid minute value %time has been caught.', ['%time' => $time_value])); | |
838 | |
839 $date_value = '2012-12-01'; | |
840 $time_value = '12:15:99'; | |
841 $edit = [ | |
842 "{$field_name}[0][value][date]" => $date_value, | |
843 "{$field_name}[0][value][time]" => $time_value, | |
844 ]; | |
845 $this->drupalPostForm(NULL, $edit, t('Save')); | |
846 $this->assertText('date is invalid', format_string('Invalid second value %time has been caught.', ['%time' => $time_value])); | |
847 } | |
848 | |
849 /** | |
850 * Tests that 'Date' field storage setting form is disabled if field has data. | |
851 */ | |
852 public function testDateStorageSettings() { | |
853 // Create a test content type. | |
854 $this->drupalCreateContentType(['type' => 'date_content']); | |
855 | |
856 // Create a field storage with settings to validate. | |
857 $field_name = Unicode::strtolower($this->randomMachineName()); | |
858 $field_storage = FieldStorageConfig::create([ | |
859 'field_name' => $field_name, | |
860 'entity_type' => 'node', | |
861 'type' => 'datetime', | |
862 'settings' => [ | |
863 'datetime_type' => 'date', | |
864 ], | |
865 ]); | |
866 $field_storage->save(); | |
867 $field = FieldConfig::create([ | |
868 'field_storage' => $field_storage, | |
869 'field_name' => $field_name, | |
870 'bundle' => 'date_content', | |
871 ]); | |
872 $field->save(); | |
873 | |
874 entity_get_form_display('node', 'date_content', 'default') | |
875 ->setComponent($field_name, [ | |
876 'type' => 'datetime_default', | |
877 ]) | |
878 ->save(); | |
879 $edit = [ | |
880 'title[0][value]' => $this->randomString(), | |
881 'body[0][value]' => $this->randomString(), | |
882 $field_name . '[0][value][date]' => '2016-04-01', | |
883 ]; | |
884 $this->drupalPostForm('node/add/date_content', $edit, t('Save')); | |
885 $this->drupalGet('admin/structure/types/manage/date_content/fields/node.date_content.' . $field_name . '/storage'); | |
886 $result = $this->xpath("//*[@id='edit-settings-datetime-type' and contains(@disabled, 'disabled')]"); | |
887 $this->assertEqual(count($result), 1, "Changing datetime setting is disabled."); | |
888 $this->assertText('There is data for this field in the database. The field settings can no longer be changed.'); | |
889 } | |
890 | |
891 } |