first commit

This commit is contained in:
2024-07-15 12:33:27 +02:00
commit ce50ae282b
22084 changed files with 2623791 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
<?php
/**
* @file
* Provides database changes for testing the daterange formatter upgrade path.
*
* @see \Drupal\Tests\datetime_range\Functional\DateRangeFormatterSettingsUpdateTest
*/
use Drupal\Core\Database\Database;
use Drupal\field\Entity\FieldStorageConfig;
$connection = Database::getConnection();
// Add all datetime_range_removed_post_updates() as existing updates.
require_once __DIR__ . '/../../../../datetime_range/datetime_range.post_update.php';
$existing_updates = $connection->select('key_value')
->fields('key_value', ['value'])
->condition('collection', 'post_update')
->condition('name', 'existing_updates')
->execute()
->fetchField();
$existing_updates = unserialize($existing_updates);
$existing_updates = array_merge(
$existing_updates,
array_keys(datetime_range_removed_post_updates())
);
$connection->update('key_value')
->fields(['value' => serialize($existing_updates)])
->condition('collection', 'post_update')
->condition('name', 'existing_updates')
->execute();
// Add a new timestamp field 'field_datetime_range'.
$connection->insert('config')
->fields(['collection', 'name', 'data'])->values([
'collection' => '',
'name' => 'field.storage.node.field_datetime_range',
'data' => $field_storage = 'a:16:{s:4:"uuid";s:36:"a01264e6-2821-4b94-bc79-ba2b346795bb";s:8:"langcode";s:2:"en";s:6:"status";b:1;s:12:"dependencies";a:1:{s:6:"module";a:2:{i:0;s:14:"datetime_range";i:1;s:4:"node";}}s:2:"id";s:25:"node.field_datetime_range";s:10:"field_name";s:20:"field_datetime_range";s:11:"entity_type";s:4:"node";s:4:"type";s:9:"daterange";s:8:"settings";a:1:{s:13:"datetime_type";s:8:"datetime";}s:6:"module";s:14:"datetime_range";s:6:"locked";b:0;s:11:"cardinality";i:1;s:12:"translatable";b:1;s:7:"indexes";a:0:{}s:22:"persist_with_no_fields";b:0;s:14:"custom_storage";b:0;}',
])->values([
'collection' => '',
'name' => 'field.field.node.page.field_datetime_range',
'data' => 'a:16:{s:4:"uuid";s:36:"678b9e68-cff5-4b2e-9111-43e5d9d6c826";s:8:"langcode";s:2:"en";s:6:"status";b:1;s:12:"dependencies";a:2:{s:6:"config";a:2:{i:0;s:39:"field.storage.node.field_datetime_range";i:1;s:14:"node.type.page";}s:6:"module";a:1:{i:0;s:14:"datetime_range";}}s:2:"id";s:30:"node.page.field_datetime_range";s:10:"field_name";s:20:"field_datetime_range";s:11:"entity_type";s:4:"node";s:6:"bundle";s:4:"page";s:5:"label";s:14:"datetime range";s:11:"description";s:0:"";s:8:"required";b:0;s:12:"translatable";b:0;s:13:"default_value";a:0:{}s:22:"default_value_callback";s:0:"";s:8:"settings";a:0:{}s:10:"field_type";s:9:"daterange";}',
])->execute();
$connection->insert('key_value')
->fields(['collection', 'name', 'value'])
->values([
'collection' => 'config.entity.key_store.field_config',
'name' => 'uuid:678b9e68-cff5-4b2e-9111-43e5d9d6c826',
'value' => 'a:1:{i:0;s:42:"field.field.node.page.field_datetime_range";}',
])
->values([
'collection' => 'config.entity.key_store.field_storage_config',
'name' => 'uuid:a01264e6-2821-4b94-bc79-ba2b346795bb',
'value' => 'a:1:{i:0;s:39:"field.storage.node.field_datetime_range";}',
])
->values([
'collection' => 'entity.storage_schema.sql',
'name' => 'node.field_schema_data.field_datetime_range',
'value' => 'a:2:{s:26:"node__field_datetime_range";a:4:{s:11:"description";s:49:"Data storage for node field field_datetime_range.";s:6:"fields";a:8:{s:6:"bundle";a:5:{s:4:"type";s:13:"varchar_ascii";s:6:"length";i:128;s:8:"not null";b:1;s:7:"default";s:0:"";s:11:"description";s:88:"The field instance bundle to which this row belongs, used when deleting a field instance";}s:7:"deleted";a:5:{s:4:"type";s:3:"int";s:4:"size";s:4:"tiny";s:8:"not null";b:1;s:7:"default";i:0;s:11:"description";s:60:"A boolean indicating whether this data item has been deleted";}s:9:"entity_id";a:4:{s:4:"type";s:3:"int";s:8:"unsigned";b:1;s:8:"not null";b:1;s:11:"description";s:38:"The entity id this data is attached to";}s:11:"revision_id";a:4:{s:4:"type";s:3:"int";s:8:"unsigned";b:1;s:8:"not null";b:1;s:11:"description";s:47:"The entity revision id this data is attached to";}s:8:"langcode";a:5:{s:4:"type";s:13:"varchar_ascii";s:6:"length";i:32;s:8:"not null";b:1;s:7:"default";s:0:"";s:11:"description";s:37:"The language code for this data item.";}s:5:"delta";a:4:{s:4:"type";s:3:"int";s:8:"unsigned";b:1;s:8:"not null";b:1;s:11:"description";s:67:"The sequence number for this data item, used for multi-value fields";}s:26:"field_datetime_range_value";a:4:{s:11:"description";s:21:"The start date value.";s:4:"type";s:7:"varchar";s:6:"length";i:20;s:8:"not null";b:1;}s:30:"field_datetime_range_end_value";a:4:{s:11:"description";s:19:"The end date value.";s:4:"type";s:7:"varchar";s:6:"length";i:20;s:8:"not null";b:1;}}s:11:"primary key";a:4:{i:0;s:9:"entity_id";i:1;s:7:"deleted";i:2;s:5:"delta";i:3;s:8:"langcode";}s:7:"indexes";a:4:{s:6:"bundle";a:1:{i:0;s:6:"bundle";}s:11:"revision_id";a:1:{i:0;s:11:"revision_id";}s:26:"field_datetime_range_value";a:1:{i:0;s:26:"field_datetime_range_value";}s:30:"field_datetime_range_end_value";a:1:{i:0;s:30:"field_datetime_range_end_value";}}}s:35:"node_revision__field_datetime_range";a:4:{s:11:"description";s:61:"Revision archive storage for node field field_datetime_range.";s:6:"fields";a:8:{s:6:"bundle";a:5:{s:4:"type";s:13:"varchar_ascii";s:6:"length";i:128;s:8:"not null";b:1;s:7:"default";s:0:"";s:11:"description";s:88:"The field instance bundle to which this row belongs, used when deleting a field instance";}s:7:"deleted";a:5:{s:4:"type";s:3:"int";s:4:"size";s:4:"tiny";s:8:"not null";b:1;s:7:"default";i:0;s:11:"description";s:60:"A boolean indicating whether this data item has been deleted";}s:9:"entity_id";a:4:{s:4:"type";s:3:"int";s:8:"unsigned";b:1;s:8:"not null";b:1;s:11:"description";s:38:"The entity id this data is attached to";}s:11:"revision_id";a:4:{s:4:"type";s:3:"int";s:8:"unsigned";b:1;s:8:"not null";b:1;s:11:"description";s:47:"The entity revision id this data is attached to";}s:8:"langcode";a:5:{s:4:"type";s:13:"varchar_ascii";s:6:"length";i:32;s:8:"not null";b:1;s:7:"default";s:0:"";s:11:"description";s:37:"The language code for this data item.";}s:5:"delta";a:4:{s:4:"type";s:3:"int";s:8:"unsigned";b:1;s:8:"not null";b:1;s:11:"description";s:67:"The sequence number for this data item, used for multi-value fields";}s:26:"field_datetime_range_value";a:4:{s:11:"description";s:21:"The start date value.";s:4:"type";s:7:"varchar";s:6:"length";i:20;s:8:"not null";b:1;}s:30:"field_datetime_range_end_value";a:4:{s:11:"description";s:19:"The end date value.";s:4:"type";s:7:"varchar";s:6:"length";i:20;s:8:"not null";b:1;}}s:11:"primary key";a:5:{i:0;s:9:"entity_id";i:1;s:11:"revision_id";i:2;s:7:"deleted";i:3;s:5:"delta";i:4;s:8:"langcode";}s:7:"indexes";a:4:{s:6:"bundle";a:1:{i:0;s:6:"bundle";}s:11:"revision_id";a:1:{i:0;s:11:"revision_id";}s:26:"field_datetime_range_value";a:1:{i:0;s:26:"field_datetime_range_value";}s:30:"field_datetime_range_end_value";a:1:{i:0;s:30:"field_datetime_range_end_value";}}}}',
])
->execute();
$data = $connection->select('key_value')
->fields('key_value', ['value'])
->condition('collection', 'entity.definitions.installed')
->condition('name', 'node.field_storage_definitions')
->execute()
->fetchField();
$data = unserialize($data);
$data['field_datetime_range'] = new FieldStorageConfig(unserialize($field_storage));
$connection->update('key_value')
->fields(['value' => serialize($data)])
->condition('collection', 'entity.definitions.installed')
->condition('name', 'node.field_storage_definitions')
->execute();
$data = $connection->select('config')
->fields('config', ['data'])
->condition('collection', '')
->condition('name', 'core.entity_view_display.node.page.default')
->execute()
->fetchField();
$data = unserialize($data);
$data['content']['field_datetime_range'] = [
'type' => 'daterange_default',
'label' => 'above',
'settings' => [
'timezone_override' => '',
'format_type' => 'medium',
'separator' => '-',
],
'third_party_settings' => [],
'weight' => 102,
'region' => 'content',
];
$connection->update('config')
->fields([
'data' => serialize($data),
])
->condition('collection', '')
->condition('name', 'core.entity_view_display.node.page.default')
->execute();
$extensions = $connection->select('config')
->fields('config', ['data'])
->condition('collection', '')
->condition('name', 'core.extension')
->execute()
->fetchField();
$extensions = unserialize($extensions);
$extensions['module']['datetime_range'] = 0;
$connection->update('config')
->fields([
'data' => serialize($extensions),
])
->condition('collection', '')
->condition('name', 'core.extension')
->execute();

View File

@@ -0,0 +1,12 @@
name: 'Datetime range test'
type: module
description: 'Provides a testing module for datetime_range.'
package: Testing
# version: VERSION
dependencies:
- drupal:taxonomy
# Information added by Drupal.org packaging script on 2024-07-04
version: '10.3.1'
project: 'drupal'
datestamp: 1720094222

View File

@@ -0,0 +1,17 @@
<?php
/**
* @file
* Contains datetime_range_test.module.
*/
/**
* Implements hook_entity_type_alter().
*/
function datetime_range_test_entity_type_alter(array &$entity_types) {
// Inhibit views data for the 'taxonomy_term' entity type in order to cover
// the case when an entity type provides no views data.
// @see https://www.drupal.org/project/drupal/issues/2995578
// @see \Drupal\Tests\datetime_range\Kernel\Views\EntityTypeWithoutViewsDataTest
$entity_types['taxonomy_term']->setHandlerClass('views_data', NULL);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\datetime_range\Functional;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
/**
* Tests the update path for daterange formatter settings.
*
* @group datetime
*/
class DateRangeFormatterSettingsUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'node',
'datetime',
'datetime_range',
];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles(): void {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-9.4.0.bare.standard.php.gz',
__DIR__ . '/../../fixtures/update/drupal.daterange-formatter-settings-2827055.php',
];
}
/**
* Tests update path for the 'from_to' formatter setting.
*
* @covers \datetime_range_post_update_from_to_configuration
*/
public function testPostUpdateDateRangeFormatter(): void {
$config_factory = \Drupal::configFactory();
// Check that 'from_to' is missing before update.
$settings = $config_factory->get('core.entity_view_display.node.page.default')->get('content.field_datetime_range.settings');
$this->assertArrayNotHasKey('from_to', $settings);
$this->runUpdates();
$settings = $config_factory->get('core.entity_view_display.node.page.default')->get('content.field_datetime_range.settings');
$this->assertArrayHasKey('from_to', $settings);
}
}

View File

@@ -0,0 +1,171 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\datetime_range\Functional\EntityResource\EntityTest;
use Drupal\Core\Url;
use Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItem;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\entity_test\Functional\Rest\EntityTestResourceTestBase;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use GuzzleHttp\RequestOptions;
/**
* Tests the 'daterange' field's normalization.
*
* @group datetime_range
*/
class EntityTestDateRangeTest extends EntityTestResourceTestBase {
use AnonResourceTestTrait;
/**
* The ISO date string to use throughout the test.
*
* @var string
*/
protected static $dateString = '2017-03-01T20:02:00';
/**
* Datetime Range test field name.
*
* @var string
*/
protected static $fieldName = 'field_daterange';
/**
* {@inheritdoc}
*/
protected static $modules = ['datetime_range', 'entity_test'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
// Add datetime_range field.
FieldStorageConfig::create([
'field_name' => static::$fieldName,
'type' => 'daterange',
'entity_type' => static::$entityTypeId,
'settings' => ['datetime_type' => DateRangeItem::DATETIME_TYPE_ALLDAY],
])->save();
FieldConfig::create([
'field_name' => static::$fieldName,
'entity_type' => static::$entityTypeId,
'bundle' => $this->entity->bundle(),
])->save();
// Reload entity so that it has the new field.
$this->entity = $this->entityStorage->load($this->entity->id());
$this->entity->set(static::$fieldName, [
'value' => static::$dateString,
'end_value' => static::$dateString,
]);
$this->entity->save();
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
$entity_test = EntityTest::create([
'name' => 'Llama',
'type' => static::$entityTypeId,
]);
$entity_test->setOwnerId(0);
$entity_test->save();
return $entity_test;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
return parent::getExpectedNormalizedEntity() + [
static::$fieldName => [
[
'value' => '2017-03-02T07:02:00+11:00',
'end_value' => '2017-03-02T07:02:00+11:00',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return parent::getNormalizedPostEntity() + [
static::$fieldName => [
[
'value' => '2017-03-01T20:02:00+00:00',
'end_value' => '2017-03-01T20:02:00+00:00',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function assertNormalizationEdgeCases($method, Url $url, array $request_options): void {
parent::assertNormalizationEdgeCases($method, $url, $request_options);
if ($this->entity->getEntityType()->hasKey('bundle')) {
$fieldName = static::$fieldName;
// DX: 422 when 'value' data type is incorrect.
$normalization = $this->getNormalizedPostEntity();
$normalization[static::$fieldName][0]['value'] = [
'2017', '03', '01', '21', '53', '00',
];
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
$response = $this->request($method, $url, $request_options);
$message = "Unprocessable Entity: validation failed.\n{$fieldName}.0.value: This value should be of the correct primitive type.\n";
$this->assertResourceErrorResponse(422, $message, $response);
// DX: 422 when 'end_value' is not specified.
$normalization = $this->getNormalizedPostEntity();
unset($normalization[static::$fieldName][0]['end_value']);
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
$response = $this->request($method, $url, $request_options);
$message = "Unprocessable Entity: validation failed.\n{$fieldName}.0.end_value: This value should not be null.\n";
$this->assertResourceErrorResponse(422, $message, $response);
// DX: 422 when 'end_value' data type is incorrect.
$normalization = $this->getNormalizedPostEntity();
$normalization[static::$fieldName][0]['end_value'] = [
'2017', '03', '01', '21', '53', '00',
];
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
$response = $this->request($method, $url, $request_options);
$message = "Unprocessable Entity: validation failed.\n{$fieldName}.0.end_value: This value should be of the correct primitive type.\n";
$this->assertResourceErrorResponse(422, $message, $response);
// DX: 422 when end date value is invalid.
$normalization = $this->getNormalizedPostEntity();
$value = '2017-13-55T20:02:00+00:00';
$normalization[static::$fieldName][0]['end_value'] = $value;
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
$response = $this->request($method, $url, $request_options);
$message = "The specified date \"$value\" is not in an accepted format: \"Y-m-d\\TH:i:sP\" (RFC 3339), \"Y-m-d\\TH:i:sO\" (ISO 8601).";
$this->assertResourceErrorResponse(422, $message, $response);
// @todo Expand in https://www.drupal.org/project/drupal/issues/2847041.
}
}
}

View File

@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\datetime_range\Functional;
use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
/**
* Generic module test for datetime_range.
*
* @group datetime_range
*/
class GenericTest extends GenericModuleTestBase {}

View File

@@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\datetime_range\FunctionalJavascript;
use Drupal\datetime_range\DateTimeRangeConstantsInterface;
use Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItem;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
/**
* Tests Daterange field.
*
* @group datetime
*/
class DateRangeFieldTest extends WebDriverTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'entity_test', 'field_ui', 'datetime', 'datetime_range'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->drupalLogin($this->drupalCreateUser([
'view test entity',
'administer entity_test content',
'administer content types',
'administer node fields',
'administer node display',
'bypass node access',
'administer entity_test fields',
]));
}
/**
* Tests the conditional visibility of the 'Date separator' field.
*/
public function testFromToSeparatorState(): void {
$field_name = $this->randomMachineName();
$this->drupalCreateContentType(['type' => 'date_content']);
$field_storage = FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'node',
'type' => 'daterange',
'settings' => ['datetime_type' => DateRangeItem::DATETIME_TYPE_DATE],
]);
$field_storage->save();
$field = FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => 'date_content',
]);
$field->save();
\Drupal::service('entity_display.repository')->getViewDisplay('node', 'date_content')
->setComponent($field_name, [
'type' => 'daterange_default',
'label' => 'hidden',
'settings' => [
'format_type' => 'short',
'separator' => 'THE_SEPARATOR',
],
])
->save();
$this->drupalGet("admin/structure/types/manage/date_content/display");
$page = $this->getSession()->getPage();
$page->pressButton("{$field_name}_settings_edit");
$this->assertSession()->waitForElement('css', '.ajax-new-content');
$from_to_locator = 'fields[' . $field_name . '][settings_edit_form][settings][from_to]';
$separator = $page->findField('Date separator');
// Assert that date separator field is visible if 'from_to' is set to
// BOTH.
$this->assertSession()->fieldValueEquals($from_to_locator, DateTimeRangeConstantsInterface::BOTH);
$this->assertTrue($separator->isVisible());
// Assert that the date separator is not visible if 'from_to' is set to
// START_DATE or END_DATE.
$page->selectFieldOption($from_to_locator, DateTimeRangeConstantsInterface::START_DATE);
$this->assertFalse($separator->isVisible());
$page->selectFieldOption($from_to_locator, DateTimeRangeConstantsInterface::END_DATE);
$this->assertFalse($separator->isVisible());
}
}

View File

@@ -0,0 +1,108 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\datetime_range\Kernel;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItem;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
/**
* Test datetime range field type via API.
*
* @group datetime
*/
class DateRangeItemTest extends FieldKernelTestBase {
/**
* A field storage to use in this test class.
*
* @var \Drupal\field\Entity\FieldStorageConfig
*/
protected $fieldStorage;
/**
* The field used in this test class.
*
* @var \Drupal\field\Entity\FieldConfig
*/
protected $field;
/**
* {@inheritdoc}
*/
protected static $modules = [
'datetime',
'datetime_range',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
// Add a datetime range field.
$this->fieldStorage = FieldStorageConfig::create([
'field_name' => $this->randomMachineName(),
'entity_type' => 'entity_test',
'type' => 'daterange',
'settings' => ['datetime_type' => DateRangeItem::DATETIME_TYPE_DATE],
]);
$this->fieldStorage->save();
$this->field = FieldConfig::create([
'field_storage' => $this->fieldStorage,
'bundle' => 'entity_test',
'required' => TRUE,
]);
$this->field->save();
$display_options = [
'type' => 'daterange_default',
'label' => 'hidden',
'settings' => [
'format_type' => 'fallback',
'separator' => 'UNTRANSLATED',
],
];
EntityViewDisplay::create([
'targetEntityType' => $this->field->getTargetEntityTypeId(),
'bundle' => $this->field->getTargetBundle(),
'mode' => 'default',
'status' => TRUE,
])->setComponent($this->fieldStorage->getName(), $display_options)
->save();
}
/**
* Tests the field configured for date-only.
*/
public function testDateOnly(): void {
$this->fieldStorage->setSetting('datetime_type', DateRangeItem::DATETIME_TYPE_DATE);
$field_name = $this->fieldStorage->getName();
// Create an entity.
$entity = EntityTest::create([
'name' => $this->randomString(),
$field_name => [
'value' => '2016-09-21',
'end_value' => '2016-09-21',
],
]);
// Dates are saved without a time value. When they are converted back into
// a \Drupal\datetime\DateTimeComputed object they should all have the same
// time.
$start_date = $entity->{$field_name}->start_date;
sleep(1);
$end_date = $entity->{$field_name}->end_date;
$this->assertEquals($start_date->getTimestamp(), $end_date->getTimestamp());
$this->assertEquals('12:00:00', $start_date->format('H:i:s'));
$this->assertEquals('12:00:00', $end_date->format('H:i:s'));
}
}

View File

@@ -0,0 +1,129 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\datetime_range\Kernel;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Language\Language;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\KernelTests\KernelTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
/**
* Test to ensure the datetime range separator is translatable.
*
* @group datetime
*/
class SeparatorTranslationTest extends KernelTestBase {
/**
* A field storage to use in this test class.
*
* @var \Drupal\field\Entity\FieldStorageConfig
*/
protected $fieldStorage;
/**
* The field used in this test class.
*
* @var \Drupal\field\Entity\FieldConfig
*/
protected $field;
/**
* {@inheritdoc}
*/
protected static $modules = [
'datetime',
'datetime_range',
'entity_test',
'field',
'language',
'system',
'user',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('entity_test');
$this->installEntitySchema('user');
$this->installConfig(['system']);
// Add a datetime range field.
$this->fieldStorage = FieldStorageConfig::create([
'field_name' => $this->randomMachineName(),
'entity_type' => 'entity_test',
'type' => 'daterange',
'settings' => ['datetime_type' => DateTimeItem::DATETIME_TYPE_DATE],
]);
$this->fieldStorage->save();
$this->field = FieldConfig::create([
'field_storage' => $this->fieldStorage,
'bundle' => 'entity_test',
'required' => TRUE,
]);
$this->field->save();
$display_options = [
'type' => 'daterange_default',
'label' => 'hidden',
'settings' => [
'format_type' => 'fallback',
'separator' => 'UNTRANSLATED',
],
];
EntityViewDisplay::create([
'targetEntityType' => $this->field->getTargetEntityTypeId(),
'bundle' => $this->field->getTargetBundle(),
'mode' => 'default',
'status' => TRUE,
])->setComponent($this->fieldStorage->getName(), $display_options)
->save();
}
/**
* Tests the translation of the range separator.
*/
public function testSeparatorTranslation(): void {
// Create an entity.
$entity = EntityTest::create([
'name' => $this->randomString(),
$this->fieldStorage->getName() => [
'value' => '2016-09-20',
'end_value' => '2016-09-21',
],
]);
// Verify the untranslated separator.
$display = EntityViewDisplay::collectRenderDisplay($entity, 'default');
$build = $display->build($entity);
$output = $this->container->get('renderer')->renderRoot($build);
$this->assertStringContainsString('UNTRANSLATED', (string) $output);
// Translate the separator.
ConfigurableLanguage::createFromLangcode('nl')->save();
/** @var \Drupal\language\ConfigurableLanguageManagerInterface $language_manager */
$language_manager = $this->container->get('language_manager');
$language_manager->getLanguageConfigOverride('nl', 'core.entity_view_display.entity_test.entity_test.default')
->set('content.' . $this->fieldStorage->getName() . '.settings.separator', 'NL_TRANSLATED!')
->save();
$this->container->get('language.config_factory_override')
->setLanguage(new Language(['id' => 'nl']));
$this->container->get('cache_tags.invalidator')->invalidateTags($entity->getCacheTags());
$display = EntityViewDisplay::collectRenderDisplay($entity, 'default');
$build = $display->build($entity);
$output = $this->container->get('renderer')->renderRoot($build);
$this->assertStringContainsString('NL_TRANSLATED!', (string) $output);
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\datetime_range\Kernel\Views;
use Drupal\Core\Config\InstallStorage;
use Drupal\Core\Serialization\Yaml;
use Drupal\KernelTests\KernelTestBase;
use Drupal\views\Entity\View;
/**
* Tests datetime_range.module when an entity type provides no views data.
*
* @group datetime
*/
class EntityTypeWithoutViewsDataTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'datetime_range',
'datetime_range_test',
'node',
'system',
'taxonomy',
'text',
'user',
'views',
];
/**
* Tests the case when an entity type provides no views data.
*
* @see datetime_test_entity_type_alter()
*/
public function testEntityTypeWithoutViewsData(): void {
$view_yaml = $this->getModulePath('taxonomy') . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY . '/views.view.taxonomy_term.yml';
$values = Yaml::decode(file_get_contents($view_yaml));
$this->assertEquals(SAVED_NEW, View::create($values)->save());
}
}

View File

@@ -0,0 +1,167 @@
<?php
declare(strict_types=1);
namespace Drupal\Tests\datetime_range\Kernel\Views;
use Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItem;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\node\Entity\Node;
use Drupal\Tests\datetime\Kernel\Views\DateTimeHandlerTestBase;
use Drupal\views\Views;
/**
* Tests date-only fields.
*
* @group datetime
*/
class FilterDateTest extends DateTimeHandlerTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'datetime_test',
'node',
'datetime_range',
'field',
];
/**
* Type of the field.
*
* @var string
*/
protected static $fieldType = 'daterange';
/**
* {@inheritdoc}
*/
public static $testViews = ['test_filter_datetime'];
/**
* For offset tests, set to the current time.
*
* @var int
*/
protected static $date;
/**
* {@inheritdoc}
*
* Create nodes with relative date range of:
* yesterday - today, today - today, and today - tomorrow.
*/
protected function setUp($import_test_views = TRUE): void {
parent::setUp($import_test_views);
// Set to 'today'.
static::$date = $this->getUTCEquivalentOfUserNowAsTimestamp();
// Change field storage to date-only.
$storage = FieldStorageConfig::load('node.' . static::$fieldName);
$storage->setSetting('datetime_type', DateRangeItem::DATETIME_TYPE_DATE);
$storage->save();
// Retrieve tomorrow, today and yesterday dates.
$dates = $this->getRelativeDateValuesFromTimestamp(static::$date);
// Node 0: Yesterday - Today.
$node = Node::create([
'title' => $this->randomMachineName(8),
'type' => 'page',
'field_date' => [
'value' => $dates[2],
'end_value' => $dates[1],
],
]);
$node->save();
$this->nodes[] = $node;
// Node 1: Today - Today.
$node = Node::create([
'title' => $this->randomMachineName(8),
'type' => 'page',
'field_date' => [
'value' => $dates[1],
'end_value' => $dates[1],
],
]);
$node->save();
$this->nodes[] = $node;
// Node 2: Today - Tomorrow.
$node = Node::create([
'title' => $this->randomMachineName(8),
'type' => 'page',
'field_date' => [
'value' => $dates[1],
'end_value' => $dates[0],
],
]);
$node->save();
$this->nodes[] = $node;
// Add end date filter to the test_filter_datetime view.
/** @var \Drupal\views\Entity\View $view */
$view = \Drupal::entityTypeManager()->getStorage('view')->load('test_filter_datetime');
$field_end = static::$fieldName . '_end_value';
$display = $view->getDisplay('default');
$filter_end_date = $display['display_options']['filters'][static::$fieldName . '_value'];
$filter_end_date['id'] = $field_end;
$filter_end_date['field'] = $field_end;
$view->getDisplay('default')['display_options']['filters'][$field_end] = $filter_end_date;
$view->save();
}
/**
* Tests offsets with date-only fields.
*/
public function testDateOffsets(): void {
$view = Views::getView('test_filter_datetime');
$field_start = static::$fieldName . '_value';
$field_end = static::$fieldName . '_end_value';
// Test simple operations.
$view->initHandlers();
// Search nodes with:
// - start date greater than or equal to 'yesterday'.
// - end date lower than or equal to 'today'.
// Expected results: nodes 0 and 1.
$view->filter[$field_start]->operator = '>=';
$view->filter[$field_start]->value['type'] = 'offset';
$view->filter[$field_start]->value['value'] = '-1 day';
$view->filter[$field_end]->operator = '<=';
$view->filter[$field_end]->value['type'] = 'offset';
$view->filter[$field_end]->value['value'] = 'now';
$view->setDisplay('default');
$this->executeView($view);
$expected_result = [
['nid' => $this->nodes[0]->id()],
['nid' => $this->nodes[1]->id()],
];
$this->assertIdenticalResultset($view, $expected_result, $this->map);
$view->destroy();
// Search nodes with:
// - start date greater than or equal to 'yesterday'.
// - end date greater than 'today'.
// Expected results: node 2.
$view->initHandlers();
$view->filter[$field_start]->operator = '>=';
$view->filter[$field_start]->value['type'] = 'offset';
$view->filter[$field_start]->value['value'] = '-1 day';
$view->filter[$field_end]->operator = '>';
$view->filter[$field_end]->value['type'] = 'offset';
$view->filter[$field_end]->value['value'] = 'now';
$view->setDisplay('default');
$this->executeView($view);
$expected_result = [
['nid' => $this->nodes[2]->id()],
];
$this->assertIdenticalResultset($view, $expected_result, $this->map);
}
}